与文档相反,OpenXML无法读取大型Excel文件

时间:2015-03-06 11:09:54

标签: c# excel openxml

documentation说:

The following code segment is used to read a very large Excel 
file using the DOM approach.

然后举个例子。我用它来实现读取700K行的相对较大的文件。我现在有这个代码:

using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(path, false)) 
{
    WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
    WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
    SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
    // no other code
}

当我开始我的程序时,我看到有多快 - 仅在五秒钟内 - 内存耗尽(> 1G)。调试器指向这行代码:

SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

所以,我需要知道OpenXML是否真的有助于读取大文件。而且,如果没有,有什么替代方案(Interop没有帮助 - 我已经检查了它。)

修改

一个额外的神秘之处。我现在得到的这段代码:

OpenXmlReader reader = OpenXmlReader.Create(worksheetPart);
while (reader.Read())
{
    if (reader.ElementType == typeof(Row))
    {
        count++;
    }                                
}

给了我count变量超过一百万行。但是,我在第一张纸上有14K,在第二张纸上有700K。这很奇怪。所以,我的额外问题是如何使用SAX方法仅解析包含数据的行。最后一个关于在OpenXML上读取大型Excel文件的谜团。这个thread中的一个人说:“事实证明工作表由于某种原因被向后枚举(所以我的三张纸中的第一张实际上是索引3”。所以,我最后一个额外的问题是如何获得表格你想要的。此刻我使用这段代码:

WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
WorksheetPart worksheetPart =     workbookPart.WorksheetParts.First();

但是考虑到说的话,我不确定在我的情况下我会真正得到第一张工作表。

1 个答案:

答案 0 :(得分:4)

您似乎有几个问题,我会尝试逐一解决。

  

所以,我需要知道OpenXML是否真的有助于读取大文件。而且,如果没有,有什么替代方案(Interop没有帮助 - 我已经检查过了。)

是的,OpenXml SDK非常适合读取大文件,但您可能需要使用SAX方法而不是DOM方法。从您引用的相同文档:

  

但是,DOM方法需要将整个Open XML部分加载到内存中,这在使用非常大的文件时会导致Out of Memory异常....当您需要处理非常大的文件时,请考虑使用SAX。 / p>

DOM方法将整个工作表加载到内存中,对于大型工作表可能会导致内存不足异常。使用SAX方法,您可以依次读取每个元素,从而显着降低内存消耗。

  

所以,我的额外问题是如何使用SAX方法仅解析数据行

仅使用SDK获取包含数据(或至少存在于XML中的行)的行。您似乎已经将此问作为一个单独的问题,我已经更详细地回答了这个问题,但基本上您是使用问题中的代码查看每个行元素的开头和结尾。有关详细信息,请参阅我对Why does OpenXML read rows twice问题的回答。

  

所以,我最后一个额外的问题是如何获得你想要的纸张。

您需要按名称查找SheetWorkbookId的后代。完成后,您可以使用其WorksheetPart获取using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filename, false)) { WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart; Sheet sheet = workbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).First(); if (sheet != null) { WorksheetPart worksheetPart = workbookPart.GetPartById(sheet.Id) as WorksheetPart; //read worksheetPart... } }

{{1}}