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();
但是考虑到说的话,我不确定在我的情况下我会真正得到第一张工作表。
答案 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问题的回答。
所以,我最后一个额外的问题是如何获得你想要的纸张。
您需要按名称查找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...
}
}
:
{{1}}