注意:此参考解决方案只是针对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. input响应慢问题解决办法

    input[file]标签的accept属性可用于指定上传文件的 MIME类型 . 例如,想要实现默认上传图片文件的代码,代码可如下: <input type="file" ...

  2. windows端口占用处理工具

    一.描述 笔者在最近使用tomcat时,老是会遇到这种端口占用的问题,便写了这个小的exe,用于解决windows下的端口占用问题. 好吧,其实是我实在记不住CMD下的那几行命令.这玩意的实现比较简单 ...

  3. [LeetCode] Friend Circles 朋友圈

    There are N students in a class. Some of them are friends, while some are not. Their friendship is t ...

  4. 【LeetCode】49. Group Anagrams

    题目: Given an array of strings, group anagrams together. For example, given: ["eat", " ...

  5. 你猜这个题输出啥?-- java基础概念

    最近在看java编程思想,大部分内容都觉得没啥意思,但是突然看到一个基本概念(似乎都忘了),于是写了测试题,我想这辈子也不会忘这个概念了. 题目如下: public class Suber exten ...

  6. Echarts笔记——使用AJAX填充数据

    最近把编辑器从Sublime换成HBuilder,感觉好用很多啊,可能自己插件没弄好吧.不不过HBuilder的启动速度确实慢,放机械盘启动要7-13秒,还好有固态. 因为项目需要,这周上手了百度的E ...

  7. 【总算解决了】A network-related or instance-specific error occurred while establishing a connection to SQL Server

    给别人做的网站莫名其妙连接不上数据库.百度了好多,总算知道自己的错在哪了. 报 "A network-related or instance-specific error occurred  ...

  8. 简约的HTML5音乐播放器插件

    从我刚开始接触前端的时候就想写一个能播放音乐的小程序,刚开始写的时候虽然可以放,但是确实很慢,很卡,有很多可以优化的地方.最近在前一个版本的基础上重写了一个音乐播放器的插件,速度还可以吧 因为追求简约 ...

  9. Servlet启动的时机

    Servlet启动的时机有两个:1.在用户第一次请求时:2.在web应用启动之时. 在web.xml 文件中配置 格式 <servlet> <servlet-name>**** ...

  10. 2017寒假零基础学习Python系列之函数之 定义默认参数

    在定义函数时,可以有默认参数例如Python自带的函数int(),其实就是两个参数,我们既可以传一个参数,又可以传两个参数 int(') >>>123 int(',8) 83 int ...