注意:此参考解决方案只是针对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包:

        <dependency>
<groupId>com.monitorjbl</groupId>
<artifactId>xlsx-streamer</artifactId>
<version>1.2.0</version>
</dependency>

使用代码如下:

    @Test
public void testLoad() throws Exception{
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

Java中使用POI读取大的Excel文件或者输入流时发生out of memory异常参考解决方案的更多相关文章

  1. Java中使用poi导入、导出Excel

    一.介绍 当前B/S模式已成为应用开发的主流,而在企业办公系统中,常常有客户这样子要求:你要把我们的报表直接用Excel打开(电信系统.银行系统).或者是:我们已经习惯用Excel打印.这样在我们实际 ...

  2. Java 使用Apache POI读取和写入Excel表格

    1,引入所用的包 <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxm ...

  3. java使用org.apache.poi读取与保存EXCEL文件

    一.读EXCEL文件 package com.ruijie.wis.cloud.utils; import java.io.FileInputStream; import java.io.FileNo ...

  4. Java使用POI读取和写入Excel指南

    Java使用POI读取和写入Excel指南 做项目时经常有通过程序读取Excel数据,或是创建新的Excel并写入数据的需求: 网上很多经验教程里使用的POI版本都比较老了,一些API在新版里已经废弃 ...

  5. java使用poi读取doc和docx文件(maven自动导入依赖包)

    java使用poi读取doc和docx文件(maven自动导入依赖包) 于是在网上搜寻了一阵之后才发现原来doc文档和excel一样不能用普通的io流的方法来读取,而是也需要用poi,于是进行了一番尝 ...

  6. lucent检索技术之创建索引:使用POI读取txt/word/excel/ppt/pdf内容

    在使用lucent检索文档时,必须先为各文档创建索引.索引的创建即读出文档信息(如文档名称.上传时间.文档内容等),然后再经过分词建索引写入到索引文件里.这里主要是总结下读取各类文档内容这一步. 一. ...

  7. 如何用 php 读取一个很大的 excel 文件。

    这个程序是用php 读取一个很大的excel文件, 先将 excel 文件保存成csv 文件, 然后利用 迭代器 逐行读取 excel 单元格的值, 拿到值以后 做相应处理,并打印结果. <?p ...

  8. 【Java/JDBC】借助ResultSetMetaData,从数据库表中抽取字段信息存成Excel文件

    本例工程下载:https://files.cnblogs.com/files/xiandedanteng/FindNotnullColumns20191102-3.rar 工作中曾有个为42张表建立测 ...

  9. 【转】Python xlrd、xlwt、xlutils读取、修改Excel文件

    Python xlrd.xlwt.xlutils读取.修改Excel文件 一.xlrd读取excel 这里介绍一个不错的包xlrs,可以工作在任何平台.这也就意味着你可以在Linux下读取Excel文 ...

随机推荐

  1. View Components as Tag Helpers,离在线模板编辑又进一步

    在asp.net core mvc中增加了ViewComponent(视图组件)的概念,视图组件有点类似部分视图,但是比部分视图功能更加强大,它更有点像一个控制器. 使用方法 1,定义类派生自View ...

  2. nmon用法

    一.简介 nmon是一个简单的性能监测工具,可以监测CPU.内存.网络等的使用情况.它是一个系统监视.调优.性能测试工具,它能一次性提供大量性能相关的信息. 二.安装与执行 下载地址:http://n ...

  3. a链接传递邮箱参数

    <?php class TesthuliAction extends CommonAction{ public function index(){ $email='78707411@qq.com ...

  4. su与sudo命令的区别

    由于su 对切换到超级权限用户root后,权限的无限制性,所以su并不能担任多个管理员所管理的系统. 如果用su 来切换到超级用户来管理系统,也不能明确哪些工作是由哪个管理员进行的操作. 特别是对于服 ...

  5. example001点击隐藏

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. 关于DOM中的model(将元素转成对象进行操作)

    DOM document (html, xml) object 将文档中的HTML元素转成js的对象 通过ID找到文档的元素转成js对象 var obj = document.getElementBy ...

  7. Linux进程/内核模型

    内核必须实现一组服务和相应的接口,应用程序则可以使用这些接口,而不是直接与硬件打交道. Linux内核主要由以下5个子系统组成:进程调度.内存管理.虚拟文件系统.进程间通信以及设备驱动. 在这个组成中 ...

  8. 使用jQuery操作 DOM

    DOM操作分为三类: 1.DOM Core:任何一种支持DOM的编程语言都可以使用它,如getElementById() 2.HTML-DOM:用于处理HTML文档,如document.forms 3 ...

  9. spring简单笔记

    1.普通注入 1)构造器注入 <constructor-arg name="id" value="100" /> #直接赋值 <constru ...

  10. JavaWeb 后端 <九> 之 JDBC加强

    一.大结果集的分页(重点,难点) 1.分批次查询:分页 2.基于数据库的分页:依赖的是数据库的分页语句(不同数据库是不同的) MySQL:每页显示10条. select * from XXX limi ...