最近需要处理一个比较大的excel文件,但是poi在处理文件时会抛出OOM导致程序崩溃,查看官方文档看到可以以流式的方式读取excel避免读取大文件时的OOM。本文主要记述xls的处理。

环境模拟

先准备一个大的excel文件(xls大小8M),再将jvm的heap缩小到100m(JVM 参数 -Xmx100m)用于模拟OOM

并使用参数在OOM时dump内存 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d://dump.hprof

使用HSSF读取

    public static void main(String [] args) throws IOException {
InputStream is = new FileInputStream("d://large.xls");
Workbook wb = new HSSFWorkbook(is);
}

运行之后

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.lang.Integer.valueOf(Integer.java:832)
at org.apache.poi.hssf.usermodel.HSSFSheet.getRow(HSSFSheet.java:385)
at org.apache.poi.hssf.usermodel.HSSFSheet.setPropertiesFromSheet(HSSFSheet.java:212)
at org.apache.poi.hssf.usermodel.HSSFSheet.<init>(HSSFSheet.java:145)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:353)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:398)
at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:379)
at blog.excel.EventExample.main(EventExample.java:109)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

就报出OOM,虽然文件只有8M并且heap有100m但是还是发生了OOM,使用jvisualvm查看dump的内容



可以看到创建了许多poi内部的Record(由于我excel内都是数字所以都是NumberRecord)。

使用SAX流式读取

POI提供了SAX流式读取的方式,可以减小内存的使用

//需要继承HSSFListener
public class EventExample implements HSSFListener
{
private SSTRecord sstrec; /**
* 实现接口方法用于处理每一条记录,包括workbook/row/cell
*/
@Override
public void processRecord(Record record)
{
switch (record.getSid())
{
// 标记workbook或sheet开始,这里会进行判断
case BOFRecord.sid:
BOFRecord bof = (BOFRecord) record;
if (bof.getType() == bof.TYPE_WORKBOOK)
{
System.out.println("Encountered workbook");
// assigned to the class level member
} else if (bof.getType() == bof.TYPE_WORKSHEET)
{
System.out.println("Encountered sheet reference");
}
break;
//处理sheet
case BoundSheetRecord.sid:
BoundSheetRecord bsr = (BoundSheetRecord) record;
System.out.println("New sheet named: " + bsr.getSheetname());
break;
//处理行
case RowRecord.sid:
RowRecord rowrec = (RowRecord) record;
System.out.println("Row found, first column at "
+ rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());
break;
//处理数字单元格
case NumberRecord.sid:
NumberRecord numrec = (NumberRecord) record;
System.out.println("Cell found with value " + numrec.getValue()
+ " at row " + numrec.getRow() + " and column " + numrec.getColumn());
break;
// 包含一行中所有文本单元格
case SSTRecord.sid:
sstrec = (SSTRecord) record;
for (int k = 0; k < sstrec.getNumUniqueStrings(); k++)
{
System.out.println("String table value " + k + " = " + sstrec.getString(k));
}
break;
//处理文本单元格
case LabelSSTRecord.sid:
LabelSSTRecord lrec = (LabelSSTRecord) record;
System.out.println("String cell found with value "
+ sstrec.getString(lrec.getSSTIndex()));
break;
}
} public static void main(String[] args) throws IOException
{
// 文件inputStream
FileInputStream is = new FileInputStream("d://large.xls");
POIFSFileSystem poifs = new POIFSFileSystem(is);
InputStream din = poifs.createDocumentInputStream("Workbook");
HSSFRequest req = new HSSFRequest();
// 为HSSFRequest增加listener
req.addListenerForAllRecords(new EventExample());
HSSFEventFactory factory = new HSSFEventFactory();
// 处理inputstream
factory.processEvents(req, din);
// 关闭inputstream
is.close();
din.close();
System.out.println("done.");
}
}

不足

使用以上的方法可以读取大文件,而不用担心oom发生。但是只能读到其单元格字面值,HSSF中的样式等都无法获取,而且只能进行读取无法修改、添加,这大大限制了其使用的范围。如果需要进行大文件的追加就需要后面介绍的SXSSF进行处理了。

POI-处理大Excel文件(xls)的更多相关文章

  1. POI读取/写入Excel文件

    import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io ...

  2. Apache POI 实现对 Excel 文件读写

    1. Apache POI 简介 Apache POI是Apache软件基金会的开放源码函式库. 提供API给Java应用程序对Microsoft Office格式档案读和写的功能. 老外起名字总是很 ...

  3. java中使用poi导入导出excel文件_并自定义日期格式

    Apache POI项目的使命是创造和保持java API操纵各种文件格式基于Office Open XML标准(OOXML)和微软的OLE复合文档格式(OLE2)2.总之,你可以读写Excel文件使 ...

  4. 使用(POI)SAX处理Excel文件,防止内存溢出

    POISAXReader h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-chi ...

  5. java读取excel文件(.xls,xlsx,csv)

    前提,maven工程通过poi读写excel文件,需要在pom.xml中配置依赖关系: 在<dependencies>中添加如下代码 <dependency> <grou ...

  6. Java入门开发POI读取导入Excel文件

    Apache POI是Apache开发的开源的跨平台的 Java API,提供API给Java程序对Microsoft Office格式档案进行各种操作. POI中Excel操作很简单,主要类有 HS ...

  7. C# 操作 Excel 文件(.xls 或 .xlsx)

    在.net中,常用的操作excel文件的方式,有三种: OLE DB的形式, 第三方框架NPOI, Office组件. 总结: 通过对比,在读取大数据量的excel文件,建议用OLE DB的形式,把e ...

  8. 关于NPOI导出excel文件(xls和xlsx两种格式)提示格式不符的问题

    这两天在做导出excel文件的时候遇到这个问题 本来我导出的格式是xlsx格式的,但是下载得到的文件格式变成了xls, 一开始以为是返回的contenttype设置错了 return File(ms, ...

  9. 使用poi实现生成excel文件

    import java.util.ArrayList; import javax.servlet.ServletOutputStream; import org.apache.poi.hssf.use ...

随机推荐

  1. iOS常用宏定义

    转发:https://www.douban.com/note/486674206/ #ifndef MacroDefinition_h#define MacroDefinition_h //----- ...

  2. IBATIS事务处理 - - 博客频道 - CSDN.NET

    body { font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI ...

  3. SpingMvc 中文乱码 post 方式解决方案

    Web.xml <!-- spring 中文乱码问题 --> <filter> <filter-name>encodingFilter</filter-nam ...

  4. 加载window事件

    $(document).ready()和window.onload的区别 发表于 2012-08-29 由 admin 以浏览器装载文档为例,在页面加载完毕后,浏览器会通过JavaScript为DOM ...

  5. js 日期控件laydate使用

    官网  http://sentsin.com/layui/laydate/ 1. 下载官网上的压缩包,解压后只需要复制laydate 文件夹到你的项目中; 2. 在页面引入  <script t ...

  6. (中等) HDU 5046 Airport ,DLX+可重复覆盖+二分。

    Description The country of jiuye composed by N cites. Each city can be viewed as a point in a two- d ...

  7. hadoop+海量数据面试题汇总(一)

    hadoop面试题 Q1. Name the most common InputFormats defined in Hadoop? Which one is default ? Following  ...

  8. Codeforces Education Round 11

    A(模拟+数学) 题意:在一个数列当中最少添加多少个数可以使它们两两互质,并打印出添加以后的数列 #include <iostream> #include <cstdio> # ...

  9. html 设置页脚div一直在页面底部

    先上代码 <!DOCTYPE HTML> <html lang="en" style="height: 100%; width: 100%;" ...

  10. Android控件系列之RadioButton&RadioGroup

    学习目的: 1.掌握在Android中如何建立RadioGroup和RadioButton 2.掌握RadioGroup的常用属性 3.理解RadioButton和CheckBox的区别 4.掌握Ra ...