导出Excel时触发System.OutOfMemory异常,求解决方案
解决ClosedXML导出Excel时的OutOfMemory异常
嘿,我之前在处理大数据量导出Excel时也踩过这个坑,XLWorkbook(ClosedXML库)是在内存中构建整个工作表的,当你的dt(DataTable)数据量过大时,很容易触发内存溢出异常。给你几个实用的解决思路:
1. 分批写入数据,避免一次性加载全量数据
不要直接把整个DataTable丢给Worksheets.Add,而是先创建空工作表,然后分批将数据写入,比如每次处理1000行,能大幅降低内存占用:
using (XLWorkbook wb = new XLWorkbook()) { string db = Request.QueryString["DB"].ToString().Replace("-", "_"); // 注意你代码里db和de变量重复定义了,这里可以修正下 var ws = wb.Worksheets.Add("Relatorio"); // 先写入表头 for (int col = 0; col < dt.Columns.Count; col++) { ws.Cell(1, col + 1).Value = dt.Columns[col].ColumnName; } // 分批写入数据,每次处理1000行 int batchSize = 1000; int rowIndex = 2; for (int i = 0; i < dt.Rows.Count; i += batchSize) { int endRow = Math.Min(i + batchSize, dt.Rows.Count); for (int row = i; row < endRow; row++) { for (int col = 0; col < dt.Columns.Count; col++) { ws.Cell(rowIndex, col + 1).Value = dt.Rows[row][col]; } rowIndex++; } // 手动触发垃圾回收(可选,视内存压力情况使用) GC.Collect(); GC.WaitForPendingFinalizers(); } // 设置表头样式 ws.Range("A1:O1").Style.Fill.BackgroundColor = XLColor.Gainsboro; ws.Range("A1:O1").Style.Font.Bold = true; // 导出到响应流 Response.Clear(); Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; Response.AddHeader("content-disposition", "attachment;filename=Relatorio.xlsx"); using (MemoryStream ms = new MemoryStream()) { wb.SaveAs(ms); ms.WriteTo(Response.OutputStream); Response.Flush(); Response.End(); } }
2. 改用支持流式导出的库(推荐大数据量场景)
ClosedXML本身不支持流式导出,如果你数据量特别大(比如10万行以上),建议换成EPPlus库,它从5.x版本开始支持流式导出,可以直接将数据写入输出流,不需要在内存中存储整个工作表,内存占用极低:
using (var package = new ExcelPackage()) { var ws = package.Workbook.Worksheets.Add("Relatorio"); // 启用流式模式加载DataTable ws.Cells["A1"].LoadFromDataTable(dt, true, TableStyles.None); package.Compatibility.IsWorksheets1Based = true; // 设置表头样式 ws.Cells["A1:O1"].Style.Fill.PatternType = ExcelFillStyle.Solid; ws.Cells["A1:O1"].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.Gainsboro); ws.Cells["A1:O1"].Style.Font.Bold = true; // 直接导出到响应流 Response.Clear(); Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; Response.AddHeader("content-disposition", "attachment;filename=Relatorio.xlsx"); package.SaveAs(Response.OutputStream); Response.Flush(); Response.End(); }
注意:使用EPPlus需要安装对应的NuGet包,商业用途需遵守其许可协议。
3. 检查并优化DataTable的数据量
先确认你的dt里到底有多少行数据,如果是几十万甚至上百万行,先考虑是否真的需要导出全量数据——比如给用户增加分页导出选项,让用户选择导出某一部分数据,从源头上减少数据量。
另外,检查DataTable中是否有不必要的大字段(比如超长字符串、二进制数据),如果有的话,尽量在导出前过滤掉或者压缩这些字段。
内容的提问来源于stack exchange,提问作者Pat
相关产品推荐
相关产品推荐

