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

OpenXml读取Excel单元格值时不识别控制面板逗号分隔符问题

解决OpenXml读取Excel时无法识别系统逗号小数点分隔符的问题

你遇到的核心问题是:OpenXml直接读取Cell.InnerText只会拿到Excel存储的原始数值(纯数字字符串),并不会自动应用系统区域设置的格式规则(比如用逗号作为小数点分隔符)。Excel里单元格显示的2,5本质上是一个数值2.5,只是通过单元格格式设置,按照你的系统区域(逗号做小数点)显示出来了。要正确读取带逗号的格式,你需要手动处理单元格的格式信息,然后将原始数值转换为符合区域格式的字符串。

下面是修改后的完整代码,包含格式处理逻辑:

using System;
using System.Globalization;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;

public static string GetCellValue(string fileName, string sheetName, string addressName)
{
    string value = string.Empty;
    using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false))
    {
        WorkbookPart wbPart = document.WorkbookPart;
        Sheet theSheet = wbPart.Workbook.Descendants<Sheet>()
            .Where(s => s.Name == sheetName).FirstOrDefault();

        if (theSheet == null)
        {
            throw new ArgumentException("指定的工作表不存在", nameof(sheetName));
        }

        WorksheetPart wsPart = (WorksheetPart)wbPart.GetPartById(theSheet.Id);
        Cell theCell = wsPart.Worksheet.Descendants<Cell>()
            .Where(c => c.CellReference == addressName).FirstOrDefault();

        if (theCell == null)
        {
            return value;
        }

        // 获取单元格的原始值
        value = theCell.InnerText;

        // 如果单元格是共享字符串类型,需要读取共享字符串表
        if (theCell.DataType != null && theCell.DataType.Value == CellValues.SharedString)
        {
            SharedStringTablePart sstPart = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
            if (sstPart != null)
            {
                value = sstPart.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
            }
        }
        // 如果是数值类型,处理格式转换
        else if (theCell.DataType != null && theCell.DataType.Value == CellValues.Number || string.IsNullOrEmpty(theCell.DataType?.Value.ToString()))
        {
            // 获取样式部分,用于解析单元格格式
            StylesPart stylesPart = wbPart.GetPartsOfType<StylesPart>().FirstOrDefault();
            if (stylesPart != null)
            {
                CellFormats cellFormats = stylesPart.Stylesheet.CellFormats;
                NumberingFormats numberingFormats = stylesPart.Stylesheet.NumberingFormats;

                // 获取单元格的样式索引
                if (theCell.StyleIndex != null)
                {
                    uint styleIndex = theCell.StyleIndex.Value;
                    CellFormat cellFormat = cellFormats.ElementAt((int)styleIndex);
                    uint numFmtId = cellFormat.NumberFormatId.Value;

                    // 检查是否是内置的数值/小数格式(这些格式会跟随系统区域调整分隔符)
                    bool isNumericFormat = numFmtId is 1 or 2 or 3 or 4 or 9 or 10 or 11 or 12 or 13 or 14;

                    if (isNumericFormat && double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out double numericValue))
                    {
                        // 使用系统当前区域格式(也就是你控制面板设置的逗号作为小数点)来格式化数值
                        value = numericValue.ToString(CultureInfo.CurrentCulture);
                    }
                }
            }
        }
    }
    return value;
}

关键说明:

  • 区分单元格类型:首先判断单元格是共享字符串还是数值类型,共享字符串需要从共享字符串表读取实际内容。
  • 解析样式格式:通过StylesPart获取单元格的格式信息,判断是否是内置的数值格式(这些格式会跟随系统区域自动调整分隔符)。
  • 区域格式转换:将原始的数值字符串转换为double类型后,使用CultureInfo.CurrentCulture(即你控制面板设置的区域)来格式化,这样就会自动把小数点替换成逗号。

额外提示:

如果你的Excel使用了自定义数字格式(比如手动设置的#.00格式,但系统区域是逗号作为小数点),你需要额外解析自定义格式字符串,替换其中的小数点为系统区域的小数点分隔符。不过对于大多数使用内置格式的场景,上面的代码已经足够解决你的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 03:47:55