.NET Core从Base64字符串生成Excel时如何保留原格式(含日期类型)
解决方案
核心思路:直接读取Excel单元格的显示文本而非原始值,同时优化大文件处理效率
1. 借助高效类库(推荐,无额外开发成本且性能可控)
使用EPPlus(适配xlsx)或NPOI(兼容xls/xlsx)这类成熟库,它们能直接获取单元格的显示文本,无需手动遍历做格式转换,且支持流式处理大文件:
EPPlus 示例(ASP.NET Core 6)
// 将Base64转为内存流 byte[] excelBytes = Convert.FromBase64String(base64String); using var stream = new MemoryStream(excelBytes); using var package = new ExcelPackage(stream); var worksheet = package.Workbook.Worksheets.First(); var xmlBuilder = new StringBuilder(); xmlBuilder.Append("<Root>"); // 流式逐行读取,降低内存占用 for (int row = worksheet.Dimension.Start.Row; row <= worksheet.Dimension.End.Row; row++) { xmlBuilder.Append("<Row>"); for (int col = worksheet.Dimension.Start.Column; col <= worksheet.Dimension.End.Column; col++) { var cell = worksheet.Cells[row, col]; // 直接获取单元格显示文本,与Excel界面一致 string cellText = cell.Text; xmlBuilder.Append($"<Column>{SecurityElement.Escape(cellText)}</Column>"); } xmlBuilder.Append("</Row>"); } xmlBuilder.Append("</Root>"); string xmlData = xmlBuilder.ToString(); // 后续将xmlData存入数据库
- 优势:
cell.Text直接返回格式化后的文本,日期保留原始显示格式;流式读取避免大文件一次性加载,效率远高于全量遍历。 - 注意:EPPlus 5+需商业授权,若需开源免费可选择NPOI。
NPOI 示例
byte[] excelBytes = Convert.FromBase64String(base64String); using var stream = new MemoryStream(excelBytes); IWorkbook workbook = WorkbookFactory.Create(stream); var worksheet = workbook.GetSheetAt(0); var xmlBuilder = new StringBuilder(); xmlBuilder.Append("<Root>"); // 用DataFormatter获取显示文本 var formatter = new DataFormatter(); for (int rowNum = worksheet.FirstRowNum; rowNum <= worksheet.LastRowNum; rowNum++) { var row = worksheet.GetRow(rowNum); if (row == null) continue; xmlBuilder.Append("<Row>"); for (int colNum = row.FirstCellNum; colNum < row.LastCellNum; colNum++) { var cell = row.GetCell(colNum); string cellText = formatter.FormatCellValue(cell); xmlBuilder.Append($"<Column>{SecurityElement.Escape(cellText)}</Column>"); } xmlBuilder.Append("</Row>"); } xmlBuilder.Append("</Root>"); string xmlData = xmlBuilder.ToString();
- 优势:完全开源免费,
DataFormatter.FormatCellValue()精准还原单元格显示格式,性能稳定。
2. 无类库方案(不推荐,开发成本高且性能难保障)
若必须不依赖第三方类库,可直接解析xlsx的底层ZIP结构:
- xlsx本质是ZIP包,解压后读取
xl/worksheets/sheet1.xml,其中<t>标签存储显示文本,<v>标签存储原始值,直接提取<t>内容即可。 - 代码示例思路:
byte[] excelBytes = Convert.FromBase64String(base64String); using var zipStream = new MemoryStream(excelBytes); using var archive = new ZipArchive(zipStream); var sheetEntry = archive.GetEntry("xl/worksheets/sheet1.xml"); if (sheetEntry == null) throw new InvalidOperationException("工作表不存在"); using var sheetStream = sheetEntry.Open(); var doc = XDocument.Load(sheetStream); XNamespace ns = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; var cells = doc.Descendants(ns + "c"); var xmlBuilder = new StringBuilder("<Root><Row>"); foreach (var cell in cells) { var tElement = cell.Element(ns + "t"); string cellText = tElement?.Value ?? cell.Element(ns + "v")?.Value ?? string.Empty; xmlBuilder.Append($"<Column>{SecurityElement.Escape(cellText)}</Column>"); // 需自行通过单元格r属性处理行分隔逻辑 } xmlBuilder.Append("</Row></Root>"); - 缺点:需自行处理命名空间、行号分割、合并单元格等复杂逻辑,大文件内存占用高,且无法解析xls二进制格式,维护成本极高。
关键注意事项
- 禁止将Excel转为文本格式后读取,否则日期会变为序列号,丢失原始格式。
- 大文件处理必须用流式逐行读取,避免一次性加载所有数据到内存,大幅提升效率。
内容的提问来源于stack exchange,提问作者BINULAL L B
相关产品推荐
相关产品推荐

