【问题标题】:Streaming through Excel data with Open XML SDK使用 Open XML SDK 流式传输 Excel 数据
【发布时间】:2018-06-01 18:13:19
【问题描述】:

我们有一个相当大的 Excel 工作簿。大约 3,300 列和数千行。

我们发现,尝试对数据执行任何操作都会导致内存使用量过高,大约为 3 GB。

似乎DocumentFormat.OpenXml 包在迭代时会在内存中保留工作表的完整对象结构。通常,我们这样做:

var workbookPart = _document.WorkbookPart;
var worksheets = workbookPart.Workbook.Descendants<Sheet>();

foreach(var worksheet in worksheets)
{
    var worksheetPart = (WorksheetPart) workbookPart.GetPartById(worksheet.Id);
    foreach(var row in worksheetPart.Worksheet.Descendants<Row>())
    {
        foreach(var cell in row.Descendants<Cell>())
        {
            var (_, value) = ParseCell(cell);
        }
    }
}

ParseCell 只需在工作簿上查找SharedStringTable 中的字符串值即可获取Cell 的内容,如果是数字,则解析该数字。

仅运行这段对ParseCell 的结果没有任何作用的代码仍会占用大量内存。

当我们分析此代码时,我们注意到在工作表中的每个单元格的堆上都有一个 Cell,尽管我们已尽最大努力使用 IEnumerable&lt;T&gt; API 来避免内存中存在大量集合。​​

这非常接近此 Nuget 包的推荐用法。

从分析来看,似乎问题在于每个Cell 都对下一个Cell 有一个强引用,Row 也是如此。

每个Cell 都有一个名为和_next 的字段,这使每个单元格都具有强根。单元格 A 强烈引用单元格 B,B 到 C,C 到 D。

Row 具有类似的结构,其中第 0 行与第 1 行有一个_next 字段,依此类推,因此对于我们经过的每个Row,它都保持对下一个@ 的强引用987654337@.

所以一切都联系在一起。当我在处理最后一个 Row 后使用 WinDbg 查看它时,工作簿中包含的 !dumpheap -stat 堆上的 Cells 数量完全相同。

我们使用此 SDK 的方式不会扩展到更多行。有没有办法更有效地使用这个包并逐行处理工作表,而不会将整个工作表的对象图保存在内存中?

【问题讨论】:

  • 对于它的价值,我知道由于 Excel 文件工作方式的性质,非常大的工作簿仍将使用大量内存 - 它们是压缩的 XML 文件。然而,这个包不仅在内存中保留了一个 30 MB 的 XML 文件,而且每个单元格中还有多个相关对象的实例。
  • 这是一个有趣的问题。我希望有人可以提供解决方案。

标签: c# openxml-sdk


【解决方案1】:

这里一个合适的解决方案是使用OpenXmlReader XML 阅读器。另一个关键是使用 Elements 而不是 Decendents 以避免在 XML 结构中查看太深。

using (var reader = OpenXmlReader.Create(worksheetPart))
{
    while (reader.Read())
    {
        if (typeof(Row).IsAssignableFrom(reader.ElementType))
        {
            var row = (Row)reader.LoadCurrentElement();
            foreach (var cell in row.Elements<Cell>())
            {
                var (_, value) = ParseCell(cell);
            }
        }
    }
}

这确实“流式传输”元素并且内存使用量极少。

【讨论】:

  • 呸,我想出了almost the exact same solution 只是稍微复杂一点的if 子句(这可能是多余的),如果我不必参加45 分钟的会议,我会得到首先。
  • @ScottChamberlain 抱歉!该死的会议。希望它至少是富有成效和乐趣的。
猜你喜欢
  • 1970-01-01
  • 2010-11-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 2018-08-01
  • 1970-01-01
  • 2011-02-03
  • 1970-01-01
相关资源
最近更新 更多