java中mypoiexception_Java中使用POI读取大的Excel文件或者输入流时发生out of memory异常参考解决方案...

注意:此参考解决方案只是针对xlsx格式的excel文件!

背景

前一段时间遇到一种情况,服务器经常宕机,而且没有规律性,查看GC日志发生了out of memory,是堆溢出导致的,分析了一下堆的dump文件,发现在发生OOM时创建了大量的String对象。最后对照时间点,发现宕机的时候业务人员在上传一个excel文件,但是这个excel文件才28MB大小,感觉应该不会引起内存溢出。后来在本地启动了服务,然后尝试上传这个excel文件,同时使用Java VisualVM监控GC情况,发现在上传的时候,创建了大量的String对象,后来老年代没有可分配空间导致了OOM。最终分析结果是,excel文件中存在几十万的空行数据,表面上看,这些空行数据跟不存在数据的行是一样的,但是POI会把这种空行数据读入到内存中,感觉这也是一个坑。

在网上搜了很长时间,发现国内网站上的解决方案真是没法看,基本上答案都差不多,没有什么有见解性的解决方法,后来在stackoverflow上找到了解决方法。算是给自己做一下备注,也想帮助一些还在坑里的人,就分享一下,只是自己的见解,有不得当的地方也请见谅。

常规读取方法

通常在读取excel文件时(.xlsx),是使用如下代码进行加载的:

FileInputStream fi = new FileInputStream("e:/2.xlsx");

XSSFWorkbook wk= new XSSFWorkbook(fi);

然后再获取对应的Sheet、Row和Cell,然后获取excel中的内容,但是这种方式POI会把文件的所有内容都加载到内存中,读取大的excel文件时很容易占用大量内存。

尝试解决方法

使用Excel Streaming Reader,这个第三方工具会把一部分的行(可以设置)缓存到内存中,在迭代时不断加载行到内存中,而不是一次性的加载所有记录到内存,这样就可以不断的读取excel内容并且不影响内存的使用。

但是这个工具也有一定的限制:只能用于读取excel的内容,写入操作不可用;可以使用getSheetAt()方法获取到对应的Sheet,因为当前只是加载了有限的row在内存中,因此不能随机访问row,即不能使用getRow(int rowNum)方法;由于行数据已经加载到了内存,因此可以随机的访问Cell数据,即可以使用getCell(int cellnum)方法。使用这个工具,建议使用迭代器来进行迭代。具体内容可以参见:https://github.com/monitorjbl/excel-streaming-reader。

在pom.xml文件中引入需要的jar包:

com.monitorjbl

xlsx-streamer

1.2.0

使用代码如下:

@Testpublic void testLoad() throwsException{

FileInputStream in= new FileInputStream("e:/2.xlsx");

Workbook wk=StreamingReader.builder()

.rowCacheSize(100) //缓存到内存中的行数,默认是10

.bufferSize(4096) //读取资源时,缓存到内存的字节大小,默认是1024

.open(in); //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件

Sheet sheet = wk.getSheetAt(0);//遍历所有的行

for(Row row : sheet) {

System.out.println("开始遍历第" + row.getRowNum() + "行数据:");//遍历所有的列

for(Cell cell : row) {

System.out.print(cell.getStringCellValue()+ " ");

}

System.out.println(" ");

}

}

参考资料:https://stackoverflow.com/questions/11891851/how-to-load-a-large-xlsx-file-with-apache-poi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值