使用EasyExcel进行文件的读取与写出(根据目录看更清晰)
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进行文件的读取与写出(根据目录看更清晰)相关推荐
- csv文件读取与写出
文章目录 一.pandas读取csv文件 二.pandas写出csv文件 三.利用csv模块读取csv文件 四.利用csv模块写出csv文件 一.pandas读取csv文件 1.导入pandas包 i ...
- 超大Excel读取和写出(支持50万+)(一)
超大Excel读取和写出(支持50万+) 一.现状 假设我们的测试或生产环境的内存条件有限,比如说2GB(当然小数据的导入和导出不在本文的讨论范围,因为导入和导出它们几乎不存在内存溢出问题). 这里, ...
- fme:AIXM4.5和5.1读取、写出和验证
fme:AIXM4.5和5.1读取.写出和验证 介绍 AIXM是航空信息交换模型格式.FME支持读取和写入AIXM版本4.5(XML)和AIXM版本5.1(GML).AIXM5.1读写需要FME201 ...
- 【C 语言】文件操作 ( 配置文件读写 | 写出或更新配置文件 | 追加键值对数据 | 更新键值对数据 )
文章目录 一.追加键值对数据 二.更新键值对数据 三.完整代码示例 一.追加键值对数据 在上一篇博客 [C 语言]文件操作 ( 配置文件读写 | 写出或更新配置文件 | 逐行遍历文件文本数据 | 获取 ...
- markdown写出项目目录结构
markdown写出项目目录结构: windows下的CMD命令tree可以很方便的得到文件夹目录树 环境:windows 功能:以树状图列出目录的内容 使用配方: tree [drive][path ...
- linux的可执行文件通常放在哪个目录中?写出该目录的路径.,实验2 Linux的基本操作与 使用vi编辑器 2010 (1)...
实验二Linux及VI的基本操作 实验目的: 1.熟悉Linux操作系统环境 2.熟悉Linux操作系统的文件结构 3.熟悉Linux操作系统的基本命令 4.熟悉Linux操作系统的文件组织方式 5. ...
- 小娴的男友小旭不幸患了一种怪病,这种怪病吞噬了他的大部分记忆,同时让他突然间不会书写符合正确语序的英文。神奇的是,虽然他写出的句子看上去杂乱无章,不过经过仔细分析可以发现,如果把单词的顺序倒过来,语法
题目描述 小娴的男友小旭不幸患了一种怪病,这种怪病吞噬了他的大部分记忆,同时让他突然间不会书写符合正确语序的英文.神奇的是,虽然他写出的句子看上去杂乱无章,不过经过仔细分析可以发现,如果把单词的顺序倒 ...
- IO学习(四)文件读取与写出
要读取一个文件,有以下几个步骤: 1.建立与文件的联系:File对象,文件必须存在 2.选择流:按字节流读取,文件输入流 InputStream FileInputStream 3.操作:byte[] ...
- java生成tiff_在Java中读取和写出TIFF图像
读取TIFF并输出BMP的最简单的方法是使用ImageIO类: BufferedImage image = ImageIO.read(inputFile); ImageIO.write(image, ...
最新文章
- 深度学习100问:什么是深监督(Deep Supervision)?
- redis有几种数据类型
- C++中逗号操作符的重载
- (转载)cmd-命令大全及详解
- [css] 举例说明css有哪些简写的属性和属性值?
- PostgreSQL全局临时表插件pgtt的使用
- java添加背景图片_Java怎么添加背景图片
- Intel 64/x86_64/x86/IA-32处理器串行化指令(2) - 参考
- 创建外网 ext_net - 每天5分钟玩转 OpenStack(104)
- 传统MVP用在项目中是真的方便还是累赘?
- 设计模式笔记之六:生产消费者模式
- ComponentPattern (组合模式)
- mysql的读写分离技术_mysql 读写分离方法
- Linux服务器时间设置命令
- 苹果蓝牙耳机怎么接电话_如何在开车时可以更安全的接电话——ROMAN R6000蓝牙耳机...
- 12、配置路由器的单臂路由(给VLAN配置网关地址)
- c语言 英文单词频率统计 哈希存储
- vue3安装vuex报错: Could not resolve dependency npm ERR peer vue@“^2.0.0“ from vuex@3.6.2
- 如何在微信中(微信公众号页面)给Vue单页应用设置标题
- endnote添加引文格式
热门文章
- Java+mysql基于ssm的大学生求职招聘系统
- 区块链加持《赛车经理》:ForceForFast 搭建由用户掌控的赛车新世界
- 炫酷的VS Code毛玻璃效果
- 【开发工具集】Process Explorer——进程资源管理器
- 【2022/1/7】Android平台启动图制作.9.png图片
- Mac下用docker安装SQL Server教程/全过程分享
- 写一个简单的打谱程序(1)
- 如何更好的运营和管理公司?
- WPS Office AI实战:Word写作如有“神”助
- 搞笑的中国片英文翻译(摘)