POI3.8解决导出大数据量excel文件时内存溢出的问题
POI3.8的SXSSF包是XSSF的一个扩展版本,支持流处理,在生成大数据量的电子表格且堆空间有限时使用。SXSSF通过限制内存中可访问的记录行数来实现其低内存利用,当达到限定值时,新一行数据的加入会引起老一行的数据刷新到硬盘。
比如内存中限制行数为100,当行号到达101时,行号为0的记录刷新到硬盘并从内存中删除,当行号到达102时,行号为1的记录刷新到硬盘,并从内存中删除,以此类推。
rowAccessWindowSize代表指定的内存中缓存记录数,默认为100,此值可以通过
new SXSSFWorkbook(int rowAccessWindowSize)或SXSSFSheet.setRandomAccessWindowSize(intwindowSize)来设置。
SXSSF在把内存数据刷新到硬盘时,是把每个SHEET生成一个临时文件,这个临时文件可能会很大,有可以会达到G级别,如果文件的过大对你来说是一个问题,你可以使用下面的方法让SXSSF来进行压缩,当然性能也会有一定的影响。
SXSSFWorkbook wb = new SXSSFWorkbook();
wb.setCompressTempFiles(true); // temp files will be gzipped
例子:
生成三个SHEET,每个SHEET有6000行记录,共18万行记录
importjava.io.FileOutputStream; importorg.apache.poi.ss.usermodel.Cell; importorg.apache.poi.ss.usermodel.Row; importorg.apache.poi.ss.usermodel.Sheet; importorg.apache.poi.ss.util.CellReference; importorg.apache.poi.xssf.streaming.SXSSFSheet; importorg.apache.poi.xssf.streaming.SXSSFWorkbook; public classSXSSFWorkBookUtil { public voidtestWorkBook() { try{ longcurr_time=System.currentTimeMillis(); introwaccess=100;//内存中缓存记录行数 /*keep 100 rowsin memory,exceeding rows will be flushed to disk*/ SXSSFWorkbook wb = newSXSSFWorkbook(rowaccess); intsheet_num=3;//生成3个SHEET for(inti=0;i<sheet_num;i++){ Sheet sh = wb.createSheet(); //每个SHEET有60000ROW for(intrownum = 0; rownum < 60000; rownum++) { Row row = sh.createRow(rownum); //每行有10个CELL for(intcellnum = 0; cellnum < 10; cellnum++) { Cell cell = row.createCell(cellnum); String address = newCellReference(cell).formatAsString(); cell.setCellValue(address); } //每当行数达到设置的值就刷新数据到硬盘,以清理内存 if(rownum%rowaccess==0){ ((SXSSFSheet)sh).flushRows(); } } } /*写数据到文件中*/ FileOutputStream os = newFileOutputStream("d:/data/poi/biggrid.xlsx"); wb.write(os); os.close(); /*计算耗时*/ System.out.println("耗时:"+(System.currentTimeMillis()-curr_time)/1000); } catch(Exception e) { e.printStackTrace(); } } }
对于不同的rowAccessWindowSize值,用上面的例子进行耗时测试,结果如下:
rowAccessWindowSize Time(s) 5000 293 1000 69 500 43 100 20 50 18 10 16 1 15
以上测试结果是在个人笔记本电脑上进行的,配置为:
Dual-Core CPU T4400 2.2GHz 2.19GHz
Memory 1.86GB
以上测试过程只是进行了一次,并没有多次测试求平均值,数据也只想表达当设置不同的rowAccessWindowSize值,耗时的一种趋势。
可见一般情况下,使用默认值100即可。
参考 http://xtadg.iteye.com/blog/1703572
http://javaflex.iteye.com/blog/1264127
2016-11-23
poi读取excel时
hssfSheet.getLastRowNum();//最后一行行标,比行数小1
hssfSheet.getRow(k).getLastCellNum();//获取列数,比最后一列列标大1
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!