【发布时间】:2012-08-05 07:33:48
【问题描述】:
我在 ASP.NET 应用程序中使用 NPOI 1.2.3.0 将相当大的 SQL 查询的结果导出到 Excel 2003 XLS 文件。
简而言之,查询结果被填充到 ADO.NET 数据表中。然后,我有一个循环遍历 DataTable 中的行的例程,并为每一行添加一行到 NPOI 电子表格。它足够智能,一旦单个工作表的行数超过 65,000 行,就会创建一个新工作表,并从新工作表的第一行开始继续行。
这种方法适用于我的一些较小的数据库查询,例如 30,000 行和 50 列,但我有一个查询,它返回 125,000 行以北,大约有 50 列,其中许多都有很好的交易文本。
我能够毫无问题地构建电子表格,但是当我尝试将生成的电子表格流式传输到浏览器时,我在调用 HSSFWorkbook 类的 Write 方法时得到一个 OutOfMemoryException。 (在内部,当 Write 方法调用类的GetBytes 方法时会发生错误。)
如果我在调用 Write 方法之前运行调试器并停止,我会看到工作簿的 Size 属性返回一个(大约)6500 万的值。
在 CodePlex 的 NPOI 项目中记录了此错误 - 请参阅标题为 Out of Memory Problems 的讨论 - 但遗憾的是没有找到解决方案。
为了完整起见,这里是引发异常的代码(具体来说,它是在workbook.Write 行上引发的)。
Using exportData As New MemoryStream()
workbook.Write(exportData)
Response.ContentType = "application/vnd.ms-excel"
Response.AddHeader("Content-Disposition", "Attachment;Filename=" & saveAsName)
Response.Clear()
Response.BinaryWrite(exportData.GetBuffer())
Response.End()
End Using
谢谢!
【问题讨论】:
-
嗨 Scott - 我记得读过有关内存流对象容量限制的文章,我认为在 32 位环境中为 512MB。您是否尝试过将 Excel 文档写入不同类型的流?
-
如果这确实是内存流本身的限制,如果需要,您可以使用 Win32 api 的包装器来避免磁盘 IO:例如:github.com/tomasr/filemap
-
@Dave,使用 FileStream 将其写入磁盘确实不会导致任何错误并成功生成电子表格。听起来 MemoryStream 可能是罪魁祸首。生产环境是64位的,所以不知道FileMap类是不是要走的路。
-
嗨 Scott - 好的,在 64 位环境中,内存流对象将处理内存中多达 2GB 的数据,所以你可能还可以,我认为 Framework 4 提供了内置包装类 -我没有研究这些,但可能值得一看 - 如果 4.0 是一个选项
-
@Dave,遗憾的是,此时不能选择 4.0。好消息是我们的暂存环境是 64 位的,所以我们可以在那里进行测试。我已经验证了我的代码适用于较小的 Excel 文件,并且非常有信心它可以工作,所以希望这是我们可以在暂存时测试的内容,以澄清问题是否存在。再次感谢您的帮助!
标签: asp.net out-of-memory npoi