EasyExcel简介

Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。

easyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。easyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

具体使用

读取文件

读取文件有两种方式:

1、使用readBySax方法进行读取,该方法适用于读取大量数据。
 EasyExcelFactory.readBySax(InputStream in, Sheet sheet, AnalysisEventListener listener)
2、使用read方法读取,该方法适用于读取少量数据。
 EasyExcelFactory.read(InputStream in, Sheet sheet)

下面就以上两种方式分别进行具体的使用

一、使用readBySax方法进行读取

1、从上述说明可以看出,该方法需要传入一个自定义监听器对象,因此我们自定义一个监听器,需要继承AnalysisEventListener并指明泛型(该泛型可以为一个自定义的类型,如User类,也可以是其他的类型,后面后具体讲述),重写invoke和doAfterAllAnalysed方法。
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;import java.util.ArrayList;
import java.util.List;/**
* @author : xukun
* @date : 2020/9/2
*/
public class AttrDataListener extends AnalysisEventListener<List<Object>> {//用于接收解析的所有数据private List<List<Object>> data = new ArrayList<>();//提供一个对外访问的方法public List<List<Object>> getData() {return data;}//记录解析的数据总数int count = 0;// easyexcel解析方式为一行一行解析,而每解析一行都会调用invoke方法// 该方法的第个参数位解析这一行的结果@Overridepublic void invoke(List<Object> objects, AnalysisContext analysisContext) {//将这一行的解析结果添加到总数据集中data.add(objects);count++;}// 所有都解析完毕后要执行的操作@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {System.out.println("解析完毕,共" + (count - 1) + "条数据");}
}
2、准备好待解析的excel文件

3、进行解析
package com.shenlan.plains.excel.listener;import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** @author : xukun* @date : 2020/9/2*/
public class ExcelTest {public static void main(String[] args) {System.out.println("===读文件===");//待解析的文件路径String filePath1 = "C:\\Users\\SLDT\\Desktop\\utf-8''区域.xlsx";//第一个sheet,从第0行开始读取数据Sheet sheet1 = new Sheet(1, 0);//创建自定义的监听对象,后面要用这个对象去获取解析的数据AttrDataListener attrDataListener = new AttrDataListener();try {//传参,进行解析;会自动调用自定义监听器中的invoke方法EasyExcelFactory.readBySax(new FileInputStream(new File(filePath1)),sheet1,attrDataListener);//得到解析的数据List<List<Object>> data = attrDataListener.getData();//打印//打印for (List<Object> d : data){System.out.println(d);}} catch (FileNotFoundException e) {e.printStackTrace();}
}
4、结果

附:泛型为指定类型:

被读取的文件:

1、该方式与类的属性一一对应,因此,我们首先创建一个User类,并且该类还要继承自BaseRowModel类同时使用@ExcelProperty注解指明表头名称和位置(若不指定,读取到的数据为空)。
package com.shenlan.plains.excel.listener;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;/**
* @author : xukun
* @date : 2020/9/3
*/
public class User extends BaseRowModel {//value的值表示该列的表头名称为“序号”  index表示该列的位置,要与被读取的文件的表头一一对应@ExcelProperty(value = "序号",index = 0)private Integer id;@ExcelProperty(value = "学号",index = 1)private String sno;@ExcelProperty(value = "姓名",index = 2)private String sname;@ExcelProperty(value = "年龄",index = 3)private Integer age;//省略Getter、Setter和toString方法
}
2、使用监听器
package com.shenlan.plains.excel.listener;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import org.apache.poi.ss.formula.functions.Count;import java.util.ArrayList;
import java.util.List;/**
* @author : xukun
* @date : 2020/9/3
*/
public class UserListener extends AnalysisEventListener<User> {private List<User> users = new ArrayList<>();public List<User> getUsers() {return users;}private int count = 0;@Overridepublic void invoke(User user, AnalysisContext context) {users.add(user);count++;}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {System.out.println("解析完毕,共解析"+count+"条数据");}
}
3、读取
package com.shenlan.plains.excel.listener;import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;import java.io.*;
import java.util.ArrayList;
import java.util.List;/**
* @author : xukun
* @date : 2020/9/2
*/
public class ExcelTest {public static void main(String[] args) {System.out.println("===读文件===");//待解析的文件路径String filePath3 = "C:\\Users\\SLDT\\Desktop\\学生.xlsx";//第一个sheet,从第1行开始读取数据(第0行,也就是表头,与User不匹配,所以从第1行开始读取)Sheet sheet3 = new Sheet(1, 1,User.class);//创建自定义的监听对象,后面要用这个对象去获取解析的数据UserListener userListener = new UserListener();try {//传参,进行解析;会自动调用自定义监听器中的invoke方法EasyExcelFactory.readBySax(new FileInputStream(new File(filePath3)),sheet3,userListener);//得到解析的数据List<User> users = userListener.getUsers();//打印for (User user : users){System.out.println(user);}} catch (FileNotFoundException e) {e.printStackTrace();}}
}

注意:在new Sheet时使用的时另一个要传入类对象的构造方法

Sheet sheet3 = new Sheet(1, 1,User.class);
4、结果

二、使用read方法进行读取

1、由于不需要使用监听器,所以我们直接准备待解析的文件即可。(其实源码里面自己创建了一个监听器对象)


待解析文件:

2、解析文件
package com.shenlan.plains.excel.listener;import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** @author : xukun* @date : 2020/9/2*/
public class ExcelTest {public static void main(String[] args) {System.out.println("===读文件===");//待解析的文件路径String filePath1 = "C:\\Users\\SLDT\\Desktop\\utf-8''区域.xlsx";//第一个sheet,从第0行开始读取数据Sheet sheet1 = new Sheet(1, 0);try {得到解析的数据List<Object> data = EasyExcelFactory.read(new FileInputStream(new File(filePath1)),sheet1);//打印for (Object d : data){System.out.println(d);}} catch (FileNotFoundException e) {e.printStackTrace();}
}
3、结果

写出文件

写文件有两种方式

第一种:生成动态表头的excel文件
第二种:生成指定表头的excel文件
下面就以上两种方式进行说明:

一、生成动态表头
1、代码如下:
package com.shenlan.plains.excel.listener;import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** @author : xukun* @date : 2020/9/2*/
public class ExcelTest {public static void main(String[] args) {System.out.println("===写文件===");String filePath2 = "C:\\Users\\SLDT\\Desktop\\test.xlsx";//第一个sheet,从第0行开始写数据Sheet sheet2 = new Sheet(1,0);sheet2.setSheetName("test");//自定义表格Table table = new Table(1);//所有表头的集合List<List<String>> head = new ArrayList<>();//后续这些表头可根据自己的需求动态生成,比如,可通过循环生成等,可能有一些业务,它的表头需要从数据库中查询得到ArrayList<String> head0 = new ArrayList<>();head0.add("姓名");//第一列表头ArrayList<String> head1 = new ArrayList<>();head1.add("学号");//第二列表头ArrayList<String> head2 = new ArrayList<>();head2.add("性别");//第三列表头head.add(head0);head.add(head1);head.add(head2);//将表头添加到表中table.setHead(head);//写try {//传参ExcelWriter writer = EasyExcelFactory.getWriter(new FileOutputStream(new File(filePath2)));writer.write0(getExcelData(), sheet2, table);writer.finish();//记住,一定要关闭资源,否则写出的文件为空System.out.println("文件写出完毕");} catch (FileNotFoundException e) {e.printStackTrace();}}/*** 写入到文件中的数据,为空时相当于一个模板* 在具体的业务中,这些数据从数据库获取*/private static List<List<String>> getExcelData() {return null;}
}
2、结果:

3、写出的文件:

二、生成指定表头
1、该方式一般生成的表头与类的属性一一对应,因此,我们首先创建一个User类,并且该类还要继承自BaseRowModel类(后续会说明原因),同时使用@ExcelProperty注解指明表头名称和位置。
package com.shenlan.plains.excel.listener;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;/*** @author : xukun* @date : 2020/9/3*/
public class User extends BaseRowModel {//value的值表示该列的表头名称为“序号”  index表示该列的位置@ExcelProperty(value = "序号",index = 0)private Integer id;@ExcelProperty(value = "学号",index = 1)private String sno;@ExcelProperty(value = "姓名",index = 2)private String sname;@ExcelProperty(value = "年龄",index = 3)private Integer age;//省略Getter、Setter和toString方法
}
2、写文件
package com.shenlan.plains.excel.listener;import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;import java.io.*;
import java.util.ArrayList;
import java.util.List;/*** @author : xukun* @date : 2020/9/2*/
public class ExcelTest {public static void main(String[] args) {//写出文件String filePath4 = "C:\\Users\\SLDT\\Desktop\\学生.xlsx";try {//传参ExcelWriter writer = EasyExcelFactory.getWriter(new FileOutputStream(new File(filePath4)));Sheet sheet4 = new Sheet(1, 0, User.class);//自定义表格Table table4 = new Table(1);writer.write0(getExcelData(), sheet4, table4);writer.finish();System.out.println("写文件完毕");} catch (FileNotFoundException e) {e.printStackTrace();}}/*** 写入到文件中的数据,为空时相当于一个模板* 在具体的业务中,这些数据从数据库获取*/private static List<List<String>> getExcelData() {return null;}
}

可以看出,在该方式中,我们使用的时Sheet的另一个重载的构造方法,在该方法中会传入一个继承自BaseRowModel的类的类对象,我们也可以从源码传参看到。

所以,前面在定义类的时候就需要让该类继承BaseRowModel类。
同时,该方式中的Table对象我们只是创建出来,并没有设置任何关于表头的属性。这是因为关于表头的信息我们都在自定义类中定义好了。

3、结果

控制台结果:

生成的表格:

至此,使用EasyExcel进行文件的读取与写出就到此结束。

使用EasyExcel进行文件的读取与写出(根据目录看更清晰)相关推荐

  1. csv文件读取与写出

    文章目录 一.pandas读取csv文件 二.pandas写出csv文件 三.利用csv模块读取csv文件 四.利用csv模块写出csv文件 一.pandas读取csv文件 1.导入pandas包 i ...

  2. 超大Excel读取和写出(支持50万+)(一)

    超大Excel读取和写出(支持50万+) 一.现状 假设我们的测试或生产环境的内存条件有限,比如说2GB(当然小数据的导入和导出不在本文的讨论范围,因为导入和导出它们几乎不存在内存溢出问题). 这里, ...

  3. fme:AIXM4.5和5.1读取、写出和验证

    fme:AIXM4.5和5.1读取.写出和验证 介绍 AIXM是航空信息交换模型格式.FME支持读取和写入AIXM版本4.5(XML)和AIXM版本5.1(GML).AIXM5.1读写需要FME201 ...

  4. 【C 语言】文件操作 ( 配置文件读写 | 写出或更新配置文件 | 追加键值对数据 | 更新键值对数据 )

    文章目录 一.追加键值对数据 二.更新键值对数据 三.完整代码示例 一.追加键值对数据 在上一篇博客 [C 语言]文件操作 ( 配置文件读写 | 写出或更新配置文件 | 逐行遍历文件文本数据 | 获取 ...

  5. markdown写出项目目录结构

    markdown写出项目目录结构: windows下的CMD命令tree可以很方便的得到文件夹目录树 环境:windows 功能:以树状图列出目录的内容 使用配方: tree [drive][path ...

  6. linux的可执行文件通常放在哪个目录中?写出该目录的路径.,实验2 Linux的基本操作与 使用vi编辑器 2010 (1)...

    实验二Linux及VI的基本操作 实验目的: 1.熟悉Linux操作系统环境 2.熟悉Linux操作系统的文件结构 3.熟悉Linux操作系统的基本命令 4.熟悉Linux操作系统的文件组织方式 5. ...

  7. 小娴的男友小旭不幸患了一种怪病,这种怪病吞噬了他的大部分记忆,同时让他突然间不会书写符合正确语序的英文。神奇的是,虽然他写出的句子看上去杂乱无章,不过经过仔细分析可以发现,如果把单词的顺序倒过来,语法

    题目描述 小娴的男友小旭不幸患了一种怪病,这种怪病吞噬了他的大部分记忆,同时让他突然间不会书写符合正确语序的英文.神奇的是,虽然他写出的句子看上去杂乱无章,不过经过仔细分析可以发现,如果把单词的顺序倒 ...

  8. IO学习(四)文件读取与写出

    要读取一个文件,有以下几个步骤: 1.建立与文件的联系:File对象,文件必须存在 2.选择流:按字节流读取,文件输入流 InputStream FileInputStream 3.操作:byte[] ...

  9. java生成tiff_在Java中读取和写出TIFF图像

    读取TIFF并输出BMP的最简单的方法是使用ImageIO类: BufferedImage image = ImageIO.read(inputFile); ImageIO.write(image, ...

最新文章

  1. 深度学习100问:什么是深监督(Deep Supervision)?
  2. redis有几种数据类型
  3. C++中逗号操作符的重载
  4. (转载)cmd-命令大全及详解
  5. [css] 举例说明css有哪些简写的属性和属性值?
  6. PostgreSQL全局临时表插件pgtt的使用
  7. java添加背景图片_Java怎么添加背景图片
  8. Intel 64/x86_64/x86/IA-32处理器串行化指令(2) - 参考
  9. 创建外网 ext_net - 每天5分钟玩转 OpenStack(104)
  10. 传统MVP用在项目中是真的方便还是累赘?
  11. 设计模式笔记之六:生产消费者模式
  12. ComponentPattern (组合模式)
  13. mysql的读写分离技术_mysql 读写分离方法
  14. Linux服务器时间设置命令
  15. 苹果蓝牙耳机怎么接电话_如何在开车时可以更安全的接电话——ROMAN R6000蓝牙耳机...
  16. 12、配置路由器的单臂路由(给VLAN配置网关地址)
  17. c语言 英文单词频率统计 哈希存储
  18. vue3安装vuex报错: Could not resolve dependency npm ERR peer vue@“^2.0.0“ from vuex@3.6.2
  19. 如何在微信中(微信公众号页面)给Vue单页应用设置标题
  20. endnote添加引文格式

热门文章

  1. Java+mysql基于ssm的大学生求职招聘系统
  2. 区块链加持《赛车经理》:ForceForFast 搭建由用户掌控的赛车新世界
  3. 炫酷的VS Code毛玻璃效果
  4. 【开发工具集】Process Explorer——进程资源管理器
  5. 【2022/1/7】Android平台启动图制作.9.png图片
  6. Mac下用docker安装SQL Server教程/全过程分享
  7. 写一个简单的打谱程序(1)
  8. 如何更好的运营和管理公司?
  9. WPS Office AI实战:Word写作如有“神”助
  10. 搞笑的中国片英文翻译(摘)