最近需要处理一个比较大的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. Visual C++ 6.0 解决win 8.1不兼容的问题。--技术宅从来不妥协

    因为目标院校复试上机需要使用这一个软件,所以在成功的路上的遇到的问题记录,避免二次犯错,在网站上下载并且安装Visual C++ 6.0,运行时会提示不兼容的问题,怎么办呢?当然不是下载他们所推荐的V ...

  2. Eclipse 快捷键使用

    ctrl+shift+T //查找当前工程下的某个类   实时提示 ctrl+shift+R//查找当前工程下的某个文件   实时提示 ctrl+/添加注释 Ctrl+1 快速修复(最经典的快捷键,就 ...

  3. 深入浅出 - Android系统移植与平台开发(一)

    深入浅出 - Android系统移植与平台开发(一) 分类: Android移植2012-09-05 14:16 16173人阅读 评论(12) 收藏 举报 androidgitgooglejdkub ...

  4. Android 中内容提供者的使用

    在Android中内容提供者主要是用于不同程序之间的数据共享.内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序的数据,另一种是创建自己的内容提供器,供其他的程序访问. 使用现 ...

  5. FZU 1058 粗心的物理学家

    这题有毒.要用long double定义,以及cout控制格式输出. #include<cstdio> #include<cstring> #include<cmath& ...

  6. IFrame跨域访问自定义高度

    由于JS禁止跨域访问,如何实现不同域的子页面将高度返回给父页面本身,是解决自定义高度的难点. JS跨域访问问题描述:应用A访问应用B的资源,由于A,B应用分别部署在不同应用服务器(tomcat)上,属 ...

  7. Android源码编译jar包BUILD_JAVA_LIBRARY 与BUILD_STATIC_JAVA_LIBRARY的区别(一)

    一般情况下,在Android源码下编译一个jar包的典型makefile(Android.mk)如下: 在文件中加入以下内容: LOCAL_PATH:= $(call my-dir)#make jar ...

  8. ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql'

    提示:ERROR 1044 (42000): Access denied for user ''@'localhost' to database 'mysql'.前两天也出现过这个问题,网上找了一个比 ...

  9. model first,DB first,code first

    code first迁移数据库1.打开程序包管理器控制台2.运行Enable-Migrations,运行之后会生成Migrations文件夹与相应的文件 Configuration.cs3.设置 Au ...

  10. Java 之 反射

    1.反射 a.意义:允许运行中的Java程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性 b.概括:运行时探究和使用编译时未知的类 c.反射的核心原理: ①JVM在加 ...