使用C# OpenXML SAX模式打开XLSX文件添加10万行失败求助
解决OpenXML SAX模式追加行到已有Excel文件的问题
我来帮你搞定这个问题!你的代码核心问题是直接创建了全新的Worksheet和SheetData,完全覆盖了原文件的表头、公式等内容,自然看不到新增的行。下面是修复后的代码,同时针对10万行的场景做了内存优化:
关键问题分析
- 原代码用
writer.WriteStartElement(new Worksheet())和writer.WriteStartElement(new SheetData())会直接替换原有工作表结构,导致原内容丢失,且没有追加行的效果 - SAX模式下需要复用原文档的SheetData结构,在其末尾追加新行,而不是重新创建
- 10万行场景下需要注意内存控制,定期Flush写入内容避免内存堆积
修复后的完整代码
string str_IntermidiateXLSPath = "c:\\testXls3.xlsx"; File.Copy("c:\\testXls.xlsx", str_IntermidiateXLSPath, true); using (SpreadsheetDocument spreadsheetDoc = SpreadsheetDocument.Open(str_IntermidiateXLSPath, true)) { spreadsheetDoc.CompressionOption = CompressionOption.SuperFast; WorkbookPart workbookPart = spreadsheetDoc.WorkbookPart; // 如果你要操作的不是第一个工作表,可根据Sheet名称定位(示例:找到名为"Sheet1"的工作表) // Sheet targetSheet = workbookPart.Workbook.Descendants<Sheet>().First(s => s.Name == "Sheet1"); // WorksheetPart worksheetPart = workbookPart.GetPartById(targetSheet.Id) as WorksheetPart; WorksheetPart worksheetPart = workbookPart.WorksheetParts.First(); Worksheet worksheet = worksheetPart.Worksheet; SheetData sheetData = worksheet.GetFirstChild<SheetData>(); // 使用SAX模式写入,保留原工作表结构 using (OpenXmlWriter writer = OpenXmlWriter.Create(worksheetPart)) { // 先写入Worksheet起始标签,保持XML结构完整性 writer.WriteStartElement(worksheet); // 先输出原工作表中除SheetData外的所有元素(保留表头、格式、公式等) foreach (OpenXmlElement element in worksheet.Elements()) { if (element is not SheetData) { writer.WriteElement(element); } } // 写入原SheetData的起始标签,准备追加新行 writer.WriteStartElement(sheetData); // 从第3行开始写入10万行(Excel行索引从1开始,i=3对应第3行) for (int i = 3; i <= 100002; i++) { Row row = new Row { RowIndex = (uint)i }; // 显式设置行索引,避免Excel行位置错乱 for (int j = 0; j < 10; j++) { string columnName = GetColumnName(j); // 转换列索引为Excel列名(A、B...) Cell cell = new Cell { CellReference = $"{columnName}{i}", // 设置单元格引用,确保Excel识别位置 DataType = CellValues.InlineString, InlineString = new InlineString { Text = new Text { Text = $"XXX" } } }; row.Append(cell); } writer.WriteElement(row); // 每写入1000行Flush一次,降低内存占用 if (i % 1000 == 0) { writer.Flush(); } } // 关闭SheetData和Worksheet标签,完成写入 writer.WriteEndElement(); writer.WriteEndElement(); } workbookPart.Workbook.Save(); } Process.Start(str_IntermidiateXLSPath); // 辅助方法:将列索引(0→A,1→B...)转换为Excel列名 private static string GetColumnName(int columnIndex) { string columnName = ""; while (columnIndex >= 0) { int remainder = columnIndex % 26; columnName = Convert.ToChar('A' + remainder) + columnName; columnIndex = columnIndex / 26 - 1; } return columnName; }
核心优化点说明
- 保留原有文档结构:不再重建Worksheet和SheetData,而是先输出原文档中除SheetData外的所有元素,确保表头、公式、格式等内容不丢失
- 规范行/单元格索引:给新行设置
RowIndex,给单元格设置CellReference,避免Excel加载时出现行位置错乱的问题 - 内存优化:每写入1000行手动Flush一次,避免大量数据堆积在内存中,适合10万行的大场景
- 灵活定位工作表:如果目标工作表不是第一个,可通过Sheet名称精准定位,适配更多场景
内容的提问来源于stack exchange,提问作者daniele
相关产品推荐
相关产品推荐

