原文链接:http://www.itsleuth.cn/post/javatool-001-easyexcel/

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便

easyexcel核心功能

  • 读任意大小的03、07版Excel不会OOM
  • 读Excel自动通过注解,把结果映射为java模型
  • 读Excel支持多sheet
  • 读Excel时候是否对Excel内容做trim()增加容错
  • 写小量数据的03版Excel(不要超过2000行)
  • 写任意大07版Excel不会OOM
  • 写Excel通过注解将表头自动写入Excel
  • 写Excel可以自定义Excel样式 如:字体,加粗,表头颜色,数据内容颜色
  • 写Excel到多个不同sheet
  • 写Excel时一个sheet可以写多个Table
  • 写Excel时候自定义是否需要写表头

快速使用

1. JAR包依赖

使用前最好咨询下最新版,或者到mvn仓库搜索一下easyexcel的最新版

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>{latestVersion}</version>
</dependency>

2. 读取Excel

使用easyexcel解析03、07版本的Excel只是ExcelTypeEnum不同,其他使用完全相同,使用者无需知道底层解析的差异。

无java模型直接把excel解析的每行结果以List返回 在ExcelListener获取解析结果
读excel代码示例如下:

@Testpublic void testExcel2003NoModel() {InputStream inputStream = getInputStream("loan1.xls");try {// 解析每行结果在listener中处理ExcelListener listener = new ExcelListener();ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener);excelReader.read();} catch (Exception e) {} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}

ExcelListener示例代码如下:

/* 解析监听器,* 每解析一行会回调invoke()方法。* 整个excel解析结束会执行doAfterAllAnalysed()方法** 下面只是我写的一个样例而已,可以根据自己的逻辑修改该类。* @author jipengfei* @date 2017/03/14*/
public class ExcelListener extends AnalysisEventListener {//自定义用于暂时存储data。//可以通过实例获取该值private List<Object> datas = new ArrayList<Object>();public void invoke(Object object, AnalysisContext context) {System.out.println("当前行:"+context.getCurrentRowNum());System.out.println(object);datas.add(object);//数据存储到list,供批量处理,或后续自己业务逻辑处理。doSomething(object);//根据自己业务做处理}private void doSomething(Object object) {//1、入库调用接口}public void doAfterAllAnalysed(AnalysisContext context) {// datas.clear();//解析结束销毁不用的资源}public List<Object> getDatas() {return datas;}public void setDatas(List<Object> datas) {this.datas = datas;}
}

有java模型映射
java模型写法如下:

public class LoanInfo extends BaseRowModel {@ExcelProperty(index = 0)private String bankLoanId;@ExcelProperty(index = 1)private Long customerId;@ExcelProperty(index = 2,format = "yyyy/MM/dd")private Date loanDate;@ExcelProperty(index = 3)private BigDecimal quota;@ExcelProperty(index = 4)private String bankInterestRate;@ExcelProperty(index = 5)private Integer loanTerm;@ExcelProperty(index = 6,format = "yyyy/MM/dd")private Date loanEndDate;@ExcelProperty(index = 7)private BigDecimal interestPerMonth;@ExcelProperty(value = {"一级表头","二级表头"})private BigDecimal sax;
}

@ExcelProperty(index = 3)数字代表该字段与excel对应列号做映射,也可以采用 @ExcelProperty(value = {“一级表头”,“二级表头”})用于解决不确切知道excel第几列和该字段映射,位置不固定,但表头的内容知道的情况。

    @Testpublic void testExcel2003WithReflectModel() {InputStream inputStream = getInputStream("loan1.xls");try {// 解析每行结果在listener中处理AnalysisEventListener listener = new ExcelListener();ExcelReader excelReader = new ExcelReader(inputStream, ExcelTypeEnum.XLS, null, listener);excelReader.read(new Sheet(1, 2, LoanInfo.class));} catch (Exception e) {} finally {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}

带模型解析与不带模型解析主要在构造new Sheet(1, 2, LoanInfo.class)时候包含class。Class需要继承BaseRowModel暂时BaseRowModel没有任何内容,后面升级可能会增加一些默认的数据。

3. 生成Excel

每行数据是List无表头

        OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx");try {ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false);//写第一个sheet, sheet1  数据全是List<String> 无模型映射关系Sheet sheet1 = new Sheet(1, 0);sheet1.setSheetName("第一个sheet");writer.write(getListString(), sheet1);writer.finish();} catch (Exception e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}

每行数据是一个java模型有表头----表头层级为一

生成Excel格式如下图:

模型写法如下:

public class ExcelPropertyIndexModel extends BaseRowModel {@ExcelProperty(value = "姓名" ,index = 0)private String name;@ExcelProperty(value = "年龄",index = 1)private String age;@ExcelProperty(value = "邮箱",index = 2)private String email;@ExcelProperty(value = "地址",index = 3)private String address;@ExcelProperty(value = "性别",index = 4)private String sax;@ExcelProperty(value = "高度",index = 5)private String heigh;@ExcelProperty(value = "备注",index = 6)private String last;
}

@ExcelProperty(value = “姓名”,index = 0) value是表头数据,默认会写在excel的表头位置,index代表第几列。

    @Testpublic void test1() throws FileNotFoundException {OutputStream out = new FileOutputStream("/Users/jipengfei/78.xlsx");try {ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);//写第一个sheet, sheet1  数据全是List<String> 无模型映射关系Sheet sheet1 = new Sheet(1, 0,ExcelPropertyIndexModel.class);writer.write(getData(), sheet1);writer.finish();} catch (Exception e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}}

每行数据是一个java模型有表头----表头层级为多层级

生成Excel格式如下图:

java模型写法如下:

public class MultiLineHeadExcelModel extends BaseRowModel {@ExcelProperty(value = {"表头1","表头1","表头31"},index = 0)private String p1;@ExcelProperty(value = {"表头1","表头1","表头32"},index = 1)private String p2;@ExcelProperty(value = {"表头3","表头3","表头3"},index = 2)private int p3;@ExcelProperty(value = {"表头4","表头4","表头4"},index = 3)private long p4;@ExcelProperty(value = {"表头5","表头51","表头52"},index = 4)private String p5;@ExcelProperty(value = {"表头6","表头61","表头611"},index = 5)private String p6;@ExcelProperty(value = {"表头6","表头61","表头612"},index = 6)private String p7;@ExcelProperty(value = {"表头6","表头62","表头621"},index = 7)private String p8;@ExcelProperty(value = {"表头6","表头62","表头622"},index = 8)private String p9;
}

写Excel写法同上,只需将ExcelPropertyIndexModel.class改为MultiLineHeadExcelModel.class

一个Excel多个sheet写法

    @Testpublic void test1() throws FileNotFoundException {OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx");try {ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false);//写第一个sheet, sheet1  数据全是List<String> 无模型映射关系Sheet sheet1 = new Sheet(1, 0);sheet1.setSheetName("第一个sheet");writer.write(getListString(), sheet1);//写第二个sheet sheet2  模型上打有表头的注解,合并单元格Sheet sheet2 = new Sheet(2, 3, MultiLineHeadExcelModel.class, "第二个sheet", null);sheet2.setTableStyle(getTableStyle1());writer.write(getModeldatas(), sheet2);//写sheet3  模型上没有注解,表头数据动态传入List<List<String>> head = new ArrayList<List<String>>();List<String> headCoulumn1 = new ArrayList<String>();List<String> headCoulumn2 = new ArrayList<String>();List<String> headCoulumn3 = new ArrayList<String>();headCoulumn1.add("第一列");headCoulumn2.add("第二列");headCoulumn3.add("第三列");head.add(headCoulumn1);head.add(headCoulumn2);head.add(headCoulumn3);Sheet sheet3 = new Sheet(3, 1, NoAnnModel.class, "第三个sheet", head);writer.write(getNoAnnModels(), sheet3);writer.finish();} catch (Exception e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}}

一个sheet中有多个表格

    @Testpublic void test2() throws FileNotFoundException {OutputStream out = new FileOutputStream("/Users/jipengfei/77.xlsx");try {ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX,false);//写sheet1  数据全是List<String> 无模型映射关系Sheet sheet1 = new Sheet(1, 0);sheet1.setSheetName("第一个sheet");Table table1 = new Table(1);writer.write(getListString(), sheet1, table1);writer.write(getListString(), sheet1, table1);//写sheet2  模型上打有表头的注解Table table2 = new Table(2);table2.setTableStyle(getTableStyle1());table2.setClazz(MultiLineHeadExcelModel.class);writer.write(getModeldatas(), sheet1, table2);//写sheet3  模型上没有注解,表头数据动态传入,此情况下模型field顺序与excel现实顺序一致List<List<String>> head = new ArrayList<List<String>>();List<String> headCoulumn1 = new ArrayList<String>();List<String> headCoulumn2 = new ArrayList<String>();List<String> headCoulumn3 = new ArrayList<String>();headCoulumn1.add("第一列");headCoulumn2.add("第二列");headCoulumn3.add("第三列");head.add(headCoulumn1);head.add(headCoulumn2);head.add(headCoulumn3);Table table3 = new Table(3);table3.setHead(head);table3.setClazz(NoAnnModel.class);table3.setTableStyle(getTableStyle2());writer.write(getNoAnnModels(), sheet1, table3);writer.write(getNoAnnModels(), sheet1, table3);writer.finish();} catch (Exception e) {e.printStackTrace();} finally {try {out.close();} catch (IOException e) {e.printStackTrace();}}}

4. 测试数据分析

从上面的性能测试可以看出easyexcel在解析耗时上比poiuserModel模式弱了一些。主要原因是我内部采用了反射做模型字段映射,中间我也加了cache,但感觉这点差距可以接受的。但在内存消耗上差别就比较明显了,easyexcel在后面文件再增大,内存消耗几乎不会增加了。但poi userModel就不一样了,简直就要爆掉了。想想一个excel解析200M,同时有20个人再用估计一台机器就挂了。

5. 百万数据解析对比

easyexcel解析百万数据内存图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVo5Q2gh-1631244928914)(https://www.itsleuth.cn/upload/2018/7/201807101724572018071110170464.png “easyexcel解析百万数据内存图”)]

poi解析百万数据内存图如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Ebaubd6-1631244928915)(https://www.itsleuth.cn/upload/2018/7/201807101732472018071110170462.png “poi解析百万数据内存图”)]

从上面两图可以看出,easyexcel解析时内存消耗很少,最多消耗不到50M;POI解析过程中直接飘升到1.5G左右,系统内存耗尽,程序挂掉。

GitHub地址:https://github.com/alibaba/easyexcel

Java解析excel工具easyexcel 助你快速简单避免OOM相关推荐

  1. java解析excel工具EasyExcel使用详情

    EasyExcel 1 EasyExcel的集成 1.1 引入依赖 1.2 模型映射 1.3 读Excel 1.4 写Excel 1.5 web上传.下载 2 自定义多Sheet页下载 2.1 工具类 ...

  2. easyexcel生成excel_阿里JAVA解析Excel工具easyexcel

    java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有 ...

  3. JAVA解析Excel工具EasyExcel

    我是傲骄鹿先生,沉淀.学习.分享.成长. 如果你觉得文章内容还可以的话,希望不吝您的「一键三连」,文章里面有不足的地方希望各位在评论区补充疑惑.见解以及面试中遇到的奇葩问法 目录 64M内存20秒读取 ...

  4. java解析excel的工具_Java 解析 Excel 工具 easyexcel

    软件介绍 easyexcel -- JAVA 解析 Excel 工具 Java 解析.生成 Excel 比较有名的框架有 Apache poi.jxl .但他们都存在一个严重的问题就是非常的耗内存,p ...

  5. 使用EasyExcel导入导出Excel报表-JAVA解析Excel工具

    一.EasyExcel概述 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内 ...

  6. java sax 解析excel,使用EasyExcel导入导出Excel报表-JAVA解析Excel工具

    1.EasyExcel概述 Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是很是的耗内存,poi有一套SAX模式的API能够必定程度的解决一些内 ...

  7. Java解析Excel工具类(兼容xls和xlsx)

    依赖jar <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml< ...

  8. Java操作excel工具easyExcel

    推荐阅读: https://blog.csdn.net/jiangjiandecsd/article/details/81115622 转载于:https://www.cnblogs.com/mxh- ...

  9. Java写Excel时OOM_JAVA解析Excel工具避免OOM

    JAVA解析Excel工具easyexcel Java解析.生成Excel比较有名的框架有Apache poi.jxl.但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一 ...

最新文章

  1. c 获取mysql列数据_转 用C API 操作MySQL数据库
  2. AutoRunner视图模式的合理使用
  3. golang 面向对象编程
  4. java web基础1Tomcat服务器基本知识
  5. c# 中文字符(全角、半角)通用处理
  6. hdu6103[尺取法] 2017多校6
  7. java excil表格开发_JAVA导出Excel电子表格的方法
  8. “非IE内核浏览器”第一阶段开发计划发布
  9. windows server 2003双网卡的问题
  10. ftp 服务器创建访问连接抱错_如何用固定IP连接FTP服务器?
  11. VDI成长之路:Windows桌面优化配置(持续更新-20120227)
  12. R语言如何做NMDS分析
  13. 微型计算机的主体,以微型计算机为主体,配上系统软件和外设就组成了微型计算机系统...
  14. vs code git 编辑器中拉取(pull) 的时候报错 [rejected] v1.0.0 -> v1.0.0 (would clobber existing tag)
  15. boost入门(一):boost简介
  16. Redis基础知识笔记
  17. MATLAB编写用户登陆界面小结——更改界面左上角图标、输入用户名提醒和输入密码隐藏
  18. 信息武器化——认知安全的必要性
  19. 用d2rq转换MySQL为RDF数据
  20. Android setEnabled() 和 setClickable() 的区别

热门文章

  1. ios开发之音频视频开发
  2. 桂电计算机系入学怎么分班,桂电研究生-()学期课程总表.doc
  3. 星光不负赶路人 农行客户点赞GBASE
  4. IOS天气预报(美化)
  5. 从前后端分离到前后端整合的“退步”(一)项目结构
  6. C#大恒相机采集图片时图片上下对称折叠了
  7. yolov4离线安装笔记
  8. 51nod 2600 小Biu的旅行
  9. 2020高考倒计时html,2020高考倒计时的励志说说
  10. 【moeCTF题解-0x01】Reverse