You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C# DocumentFormat.OpenXml读取Excel数值单元格异常问题咨询

问题分析与解决方案

嘿,我一眼就看出问题出在哪了——你把所有单元格都当成共享字符串来处理了,但数值类型的单元格根本不需要去SharedStringTable里找!这就是为什么数值单元格返回的总是第一行第一列内容的原因:你把数值本身当成了共享字符串的索引,而索引0对应的正好是共享字符串表里的第一个条目(也就是你看到的第一行第一列内容)。

核心问题拆解

Excel用不同的方式存储不同类型的单元格内容:

  • 字符串类型:会把重复的字符串统一存在SharedStringTable中,单元格的InnerText是该字符串在表中的索引,这时候你去查共享表是正确的。
  • 数值类型(数字、日期等):单元格的InnerText直接就是实际数值,而且这类单元格的DataType通常是CellValues.Number,甚至有时候不指定DataType(默认就是数值类型)。这时候如果还拿InnerText当索引去查共享表,自然会拿到错误的内容。

修正后的代码

下面是调整后的完整代码,我加了类型判断、空值处理和异常防护:

// 先获取共享字符串表,注意判空(有些Excel可能没有共享字符串表)
var sharedStringTable = workbookPart.SharedStringTablePart?.SharedStringTable;

// 去掉原有的过滤条件,因为数值单元格可能没有DataType属性,会被误过滤
List<Row> rows = sheetData.Elements<Row>().ToList();

foreach (Row row in rows)
{
    foreach (Cell cell in row.Elements<Cell>())
    {
        string cellValue = string.Empty;

        if (cell.DataType != null)
        {
            switch (cell.DataType.Value)
            {
                case CellValues.SharedString:
                    // 仅共享字符串类型才去查询共享表
                    if (sharedStringTable != null && int.TryParse(cell.InnerText, out int stringIndex))
                    {
                        var sharedStringItem = sharedStringTable.Elements<SharedStringItem>().ElementAtOrDefault(stringIndex);
                        cellValue = sharedStringItem?.InnerText ?? string.Empty;
                    }
                    break;
                case CellValues.Number:
                    // 数值类型直接读取InnerText
                    cellValue = cell.InnerText;
                    // 如果需要转成数值类型,可以在这里处理:
                    // if (double.TryParse(cellValue, out double numberValue)) { ... }
                    break;
                // 额外补充布尔类型的处理(可选)
                case CellValues.Boolean:
                    cellValue = cell.InnerText == "1" ? "True" : "False";
                    break;
            }
        }
        else
        {
            // DataType为null时,默认是数值类型
            cellValue = cell.InnerText;
        }

        Console.WriteLine(cellValue);
    }
}

关键优化点

  1. 类型区分处理:通过DataType判断单元格类型,只对共享字符串类型查询SharedStringTable。
  2. 空值防护:用?.和??处理可能的空引用,避免程序崩溃。
  3. 异常避免:用int.TryParse代替int.Parse,防止索引格式错误;用ElementAtOrDefault代替ElementAt,避免索引越界。
  4. 修正行过滤:去掉了原有的行过滤条件,避免漏掉只有数值的行(如果需要过滤空行,可以改成判断行内是否有非空单元格)。

内容的提问来源于stack exchange,提问作者asisleep

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 18:02:41