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

使用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;
}

核心优化点说明

  1. 保留原有文档结构:不再重建Worksheet和SheetData,而是先输出原文档中除SheetData外的所有元素,确保表头、公式、格式等内容不丢失
  2. 规范行/单元格索引:给新行设置RowIndex,给单元格设置CellReference,避免Excel加载时出现行位置错乱的问题
  3. 内存优化:每写入1000行手动Flush一次,避免大量数据堆积在内存中,适合10万行的大场景
  4. 灵活定位工作表:如果目标工作表不是第一个,可通过Sheet名称精准定位,适配更多场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:22:11