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
相关产品推荐
相关产品推荐

