与文档相反,OpenXML不能帮助读取大型Excel文件

该文件说:

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)。 debugging器指向这行代码:

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

所以,我需要知道OpenXML是否真的有助于读取大文件。 而且,如果不是,还有什么select(Interop不起作用 – 我已经检查过了)。

编辑

一件额外的神秘事物 这个代码我现在得到:

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

countvariables超过一百万行。 但是,我的第一张纸上有14K,第二张上有700K。 这很奇怪。 所以,我额外的问题是如何使用SAX方法parsing只有数据的行。 最后一个在OpenXML上读取大型Excel文件的秘密。 在这个线程中有一个人说:“原因是工作表是由于某种原因倒退的(所以我的三张表中的第一张实际上是索引3”,所以我最后一个额外的问题是如何得到你想要的表格。这一刻我使用这个代码:

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

但考虑到说了什么,我不确定在我的情况下,我实际上会得到第一个工作表。

你似乎有几个问题,我会试着一一解决。

所以,我需要知道OpenXML是否真的有助于读取大文件。 而且,如果不是,还有什么select(Interop不起作用 – 我已经检查过了)。

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

但是,DOM方法要求将整个Open XML部件加载到内存中,当您处理的文件非常大时,可能会导致内存不足exception….请考虑在需要处理非常大的文件时使用SAX。

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

所以,我的额外的问题是如何使用SAX方法parsing只有数据的行

您只能使用SDK获取具有数据的行(或至less存在于XML中的行)。 您似乎已经问过这个问题了,我已经详细回答了这个问题,但是基本上您可以看到每个行元素的开始和结束,使用问题中的代码。 查看我的答案为什么OpenXML读取两行的问题有关更多详细信息。

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

您需要按照Workbook名称查找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... } }