找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
  • 网友反映远安桃花岛步道破损隐患,住建部门火速处置,官方留言却遭平台屏蔽引唏嘘

    网友反映远安桃花岛步道破损隐患,住建部门

  • 网曝远安桃花岛上惊现安全隐患,钉子都出来了,周边都是孩子在玩耍

    网曝远安桃花岛上惊现安全隐患,钉子都出来

  • 被网友举报远安北万路上这辆挂人后视镜直接走掉的鄂A本田,罚单来了

    被网友举报远安北万路上这辆挂人后视镜直接

  • 网友举报这辆半挂竟公然在远安泉水冲那里闯红灯,别急,罚单已到位!

    网友举报这辆半挂竟公然在远安泉水冲那里闯

  • 好消息!武陵峡果园杨梅开园啦!老板发福利啦

    好消息!武陵峡果园杨梅开园啦!老板发福利

  • 精装修门面出租:无转让费!周边配套齐全,房东(胡)

    精装修门面出租:无转让费!周边配套齐全,

  • 厕所顶部漏水半年多维权困难 寻求帮助

    厕所顶部漏水半年多维权困难 寻求帮助

  • 远安G347国道上这辆大货车,你的罚单来了

    远安G347国道上这辆大货车,你的罚单来了

  • 紧急提醒:远安县刚刚发布暴雨橙色预警,注意避险防范

    紧急提醒:远安县刚刚发布暴雨橙色预警,注

  • 【招聘保洁熟手】

    【招聘保洁熟手】

  • 襄阳发布警情通报

    襄阳发布警情通报

  • 吐槽一下家门口的清洗街道车😔😔

    吐槽一下家门口的清洗街道车😔😔

  • 险象环生!远安万山弯道五菱神车逆行别车,罚单来了

    险象环生!远安万山弯道五菱神车逆行别车,

  • 突发!刚刚远安这条网红彩虹路边,翻了一辆车

    突发!刚刚远安这条网红彩虹路边,翻了一辆

  • 远安凤凰湾门口路段这位女司机,你的罚单来了

    远安凤凰湾门口路段这位女司机,你的罚单来

  • 【小董有个友好请求🫡】

    【小董有个友好请求🫡】

  • 一串红提,宛如秋日里的一抹亮色...

    一串红提,宛如秋日里的一抹亮色...

  • 远安汽摩协会与远安特校十年相伴,童心同行

    远安汽摩协会与远安特校十年相伴,童心同行

  • 【五月·共勉】

    【五月·共勉】

  • 当阳市公安局玉泉派出所原指导员朱心维接受纪律审查和监察调查

    当阳市公安局玉泉派出所原指导员朱心维接受

  • 远安广坪路段这辆奥迪,你的行为太危险了,你就不怕成了夹心饼干吗

    远安广坪路段这辆奥迪,你的行为太危险了,

  • 在远安洋坪路段违法超车的这辆车,你的罚单刚刚出来了

    在远安洋坪路段违法超车的这辆车,你的罚单

  • 这辆车在远安县解放路与凤德路交汇路口违停,极大交通隐患

    这辆车在远安县解放路与凤德路交汇路口违停

  • 网友反映远安城区这里的行道树上长满了白蚁,观之肉麻!不知道该找谁治

    网友反映远安城区这里的行道树上长满了白蚁

  • 【上午9点把门锁, 小飞侠这是要闹哪出? 】

    【上午9点把门锁, 小飞侠这是要闹哪出? 】

  • 湖北安广陶瓷招聘销售跟单

    湖北安广陶瓷招聘销售跟单

  • 今晚,调油价!

    今晚,调油价!

  • 必须曝光!今天上午,远安嫘祖镇广坪路段这辆婚庆公司的轻卡强行超车肇事逃逸

    必须曝光!今天上午,远安嫘祖镇广坪路段这

  • 坚强的小米辣

    坚强的小米辣

  • 远安人,这个“2026年度综合补贴”是诈骗!

    远安人,这个“2026年度综合补贴”是诈骗!

  • 查看: 8763|回复: 1

    Java解析excel工具easyexcel助你快速简单避免OOM[图]

    [复制链接]
    • 打卡等级:无名新人
    • 打卡总天数:1
    • 打卡月天数:0
    • 打卡总奖励:10
    • 最近打卡:2023-06-13 20:58:02
         
    荆楚不肖生 发表于 2018-7-19 16:26 | 显示全部楼层 |阅读模式 来自 中国–湖北–宜昌 电信

    赶紧注册,享受更多功能!查看帖内大图!

    您需要 登录 才可以下载或查看,没有账号?立即注册

    ×
    Java解析excel工具easyexcel助你快速简单避免OOM[图]
    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时候自定义是否需要写表头

    Java解析excel工具easyexcel助你快速简单避免OOM[图] Java解析、生成Excel比较有名的框架有Apache poi、jxl ...

    Java解析excel工具easyexcel助你快速简单避免OOM[图] Java解析、生成Excel比较有名的框架有Apache poi、jxl ...
    快速使用
    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代码示例如下:
    @Test
    public 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第几列和该字段映射,位置不固定,但表头的内容知道的情况。
    @Test
    public 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代表第几列。
    @Test
    public 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写法
    @Test
    public 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中有多个表格
    @Test
    public 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解析百万数据内存图如下:
    easyexcel解析百万数据内存图
    poi解析百万数据内存图如下:
    poi解析百万数据内存图
    从上面两图可以看出,easyexcel解析时内存消耗很少,最多消耗不到50M;POI解析过程中直接飘升到1.5G左右,系统内存耗尽,程序挂掉。

    百姓地盘、草根平台!(点击修改为自己的签名)客服QQ:139725796
    • 打卡等级:即来则安
    • 打卡总天数:28
    • 打卡月天数:0
    • 打卡总奖励:1687
    • 最近打卡:2026-05-27 22:10:38
         
    年轻就是资本 发表于 2018-7-20 14:53 | 显示全部楼层 来自 中国–湖北–宜昌 电信
    百姓地盘、草根平台!(点击修改为自己的签名)客服QQ:139725796
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    

    Archiver|手机版|小黑屋|认证|简介|联系我们|赤脚网[临沮网] ( 鄂ICP备18015422号|42052502000021 )

    GMT+8, 2026-6-17 22:23

    Powered by Discuz! X3.5

    © 2001-2026 Discuz! Team.

    网站内容仅代表网友个人观点,非本站认同之观点!删帖请用删帖卡,或在申请版块发帖申请,或联系【 bbs@yalj.net 】我们会尽快处理。
    声明:严禁任何人以任何形式在本站发表与中华人民共和国法律相抵触的言论!
    技术管理:远安坤哥    主办单位:远安县临沮网信息管理中心
                       
    快速回复 返回顶部 返回列表