C#读取OpenXML的CellValue返回十六进制值 如何获取Excel实际存储值
问题原因
你当前的代码仅处理了*共享字符串(SharedString)*类型的单元格,对DataType == null的单元格直接读取原始文本,这会导致读取结果不符合预期:
OpenXML中DataType为null时,单元格默认存储的是数值类型原始值,如果单元格实际是日期、百分比、货币等带格式的类型,原始值是OLE自动化日期数值、未格式化的原始数字,并非Excel界面中展示的格式化值,你误以为的十六进制格式实际是未转换的OLE日期值或者科学计数法格式的原始数字字符串。
解决方案
你需要补充处理不同的单元格类型,增加日期、布尔值、数值的转换逻辑,修改后的完整代码如下:
foreach (Row row in sheetData.Elements<Row>()) { ArrayList data = new ArrayList(); if (!firstRow) { var firstCol = true; foreach (Cell cell in row.Elements<Cell>()) { if (!firstCol) { object cellValue = string.Empty; // 处理带明确DataType的单元格 if (cell.DataType != null) { switch (cell.DataType.Value) { // 共享字符串类型 case CellValues.SharedString: if (int.TryParse(cell.InnerText, out int id)) { cellValue = workbookPart.SharedStringTablePart.SharedStringTable .Elements<SharedStringItem>().ElementAt(id).InnerText; } break; // 布尔类型 case CellValues.Boolean: cellValue = cell.InnerText == "1"; break; // 内联字符串 case CellValues.InlineString: cellValue = cell.InnerText; break; // 错误值统一返回空 case CellValues.Error: cellValue = string.Empty; break; } } // 处理数值/日期类型(DataType默认为null) else if (cell.CellValue != null) { string rawValue = cell.CellValue.Text; // 先判断是否为日期格式 if (IsCellDateType(cell, workbookPart) && double.TryParse(rawValue, out double oleDate)) { cellValue = DateTime.FromOADate(oleDate); } // 再判断是否为普通数值 else if (double.TryParse(rawValue, out double number)) { cellValue = number; } // 其他情况直接返回原始文本 else { cellValue = rawValue; } } data.Add(cellValue); } else { firstCol = false; } } rowList.Add(data); } else { firstRow = false; } }
新增判断单元格是否为日期格式的辅助方法:
private static bool IsCellDateType(Cell cell, WorkbookPart workbookPart) { if (cell.StyleIndex == null) return false; CellFormat cellFormat = (CellFormat)workbookPart.WorkbookStylesPart.Stylesheet.CellFormats .ElementAt((int)cell.StyleIndex.Value); uint formatId = cellFormat.NumberFormatId; // Excel标准日期格式的NumberFormatId范围 return (formatId is >= 14 and <= 22) || (formatId is >= 27 and <= 36) || (formatId is >= 45 and <= 47) || (formatId is >= 50 and <= 58) || formatId >= 81; }
补充说明
如果需要获取和Excel界面展示完全一致的格式化文本,可以根据NumberFormatId对应的格式规则,将原始数值格式化为对应字符串,比如格式ID为10对应mm-dd-yy,格式ID为2对应0.00。
内容的提问来源于stack exchange,提问作者Nayab Raheel
相关产品推荐
相关产品推荐

