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

OpenXML does not help to read large Excel files contrary to documentation

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 变量中给出超过一百万行。但是,我在第一个 sheet 上有 14K,在第二个 sheet 上有 700K。这很奇怪。因此,我的额外问题是如何使用 SAX 方法仅解析包含数据的行。最后一个谜团是在 OpenXML 上读取大型 Excel 文件。 thread 中的一个人说:"Turns out that the worksheets are enumerated backwards for some reason (so the first of my three sheets is actually index 3"。所以,我最后一个额外的问题是如何得到你想要的sheet。此时我使用这段代码:

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

但考虑到所说的话,我不确定我是否真的会得到第一份工作sheet。

你好像有几个问题,我会一一解答。

So, I need to know whether OpenXML really helps to read large files. And, if not, what are the alternatives (Interop does not help - I've already checked it).

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

However, the DOM approach requires loading entire Open XML parts into memory, which can cause an Out of Memory exception when you are working with really large files.... Consider using SAX when you need to handle very large files.

DOM 方法将整个 sheet 加载到内存中,对于较大的 sheet 可能会导致内存不足异常。使用 SAX 方法,您可以依次读取每个元素,从而大大减少内存消耗。

So, my extra question is how to parse only rows with data using SAX approach

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

So, my final extra question is how to get the sheet you want.

您需要按名称找到 Sheet,它是 Workbook 的后代。一旦你有了它,你就可以使用它的 Id 来获得 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...
    }
}