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. Servlet跳转到jsp页面的几种方法
  2. [HDU] 2612 Find a way - 用单源最短论经模拟的简单广搜
  3. 关于JTAG——韦东山嵌入式Linux视频学习笔记02
  4. mac电脑简单好用的非主流程序
  5. 盘点程序员开发遇到的30个问题
  6. IntelliJ IDEA 自动补全变量名称和变量类型(自动补全变量的声明内容)
  7. pip is configured with locations that require TLS/SSL, however the ssl module in Python is not avail
  8. python字典编码_Python列表,字典,元组,字符串操作,文件操作,字符编码
  9. python gil锁_python--GIL锁
  10. GPS模拟器算法(C#)
  11. Html鼠标右键菜单代码
  12. ArcGIS地形图配准并生成三维模型(附练习数据下载)
  13. 汽车电子之NFC技术
  14. stm32 代码加密
  15. 传统数据处理技术如何与大数据处理技术有机结合
  16. 用Node.js写一个爬虫来爬小说
  17. 根据P(precision)、R(recall)计算F1和iou
  18. GWAS计算BLUE值4--联合方差分析演示
  19. 通达云OA2015版及钉钉、微信办公集成产品正式发布
  20. 基于Django的论坛系统项目

热门文章

  1. 企业及个人如何有效防护网络攻击
  2. C语言二叉树的基本操作(超全)
  3. 前端点击图片,图片放大
  4. 【无标题】2021年施工升降机司机(建筑特殊工种)试题及解析及施工升降机司机(建筑特殊工种)实操考试视频
  5. python什么是装饰器_python学习之装饰器是什么?
  6. 小新pro16安装双系统Ubuntu-20.04
  7. 无线基站定位服务器,android 基站定位api
  8. 猫耳宝贝:“网络打女”身手不凡
  9. HTML5新元素(测试了大部分浏览器可用的元素,部分标签有详细讲解)
  10. webstorm字体设置大小