读文件
前言
在网上找了许多文档,大多数都太老了又或者都是互相复制。就连官方的文档也是写的对新手不够友好,因此将学习过程记录下来。
使用环境部署
这个步骤网上绝大部分都没有说,建议先和我使用相同的版本,熟悉后在更换最新版本。
在这里我使用maven管理器来管理包。
// pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>easyExcelDemo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<!--关键加上这两个包开始-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
<scope>compile</scope>
</dependency>
<!--关键加上这两个包结束-->
</dependencies>
</project>
导入后的包
一个简单的读取Excel文件
新建ExcelReaderBuilder读取流
ExcelReaderBuilder readerBuilder = EasyExcel.read();
给文件流传入Excel路径或者File对象
readerBuilder.file("C:\\***\\2021学生信息.xlsx");
// 或
readerBuilder.file(new File("C:\\***.xlsx"));
指定sheet名字,或者下标
readerBuilder.sheet("Sheet1");
为了节省内存,在这里应该加上自动关闭文件流
readerBuilder.autoCloseStream(true);
因为Excel有多个版本,需要指定版本
readerBuilder.excelType(ExcelTypeEnum.XLSX);
到了这里,已经将Excel配置到了。接下来我们来监听读取文件流。
registerReadListener会一行一行的回调到invoke
函数,只要调用返回的参数即可。读取完全部文件后会调用doAfterAllAnalysed
。
readerBuilder.registerReadListener(new AnalysisEventListener() {
@Override
public void invoke(Object o, AnalysisContext analysisContext) {
// 读完一行的回调函数操作
System.out.println(o);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 读完所有的数据后的回调函数操作
System.out.println("读完所有的数据后的回调函数操作");
}
});
到了这里,其实还不能读取到数据,因为该工作流并没有启动,我们需要构建读取器。
ExcelReader reader = readerBuilder.build();
// 构建读取器
再启动,读取全部数据
reader.readAll();
// 读取全部数据
关闭读取器
reader.finish();
// 关闭读取器
全部代码
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.support.ExcelTypeEnum;
import java.io.File;
public class Test {
public static void main(String[] args) {
ExcelReaderBuilder readerBuilder = EasyExcel.read();
// 创建一个 ExcelReader 对象
readerBuilder.file("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx");
// 获取文件对象
readerBuilder.sheet("Sheet1");
// 指定sheet名称
readerBuilder.autoCloseStream(true);
// 自动关闭流
readerBuilder.excelType(ExcelTypeEnum.XLSX);
// 设置excel类型
readerBuilder.registerReadListener(new AnalysisEventListener() {
@Override
public void invoke(Object o, AnalysisContext analysisContext) {
// 读完一行的回调函数操作
System.out.println(o);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
// 读完所有的数据后的回调函数操作
System.out.println("读完所有的数据后的回调函数操作");
}
});
ExcelReader reader = readerBuilder.build();
// 构建读取器
reader.readAll();
// 读取全部数据
reader.finish();
// 关闭读取器fanxing
}
}
优化代码
由于invoke
回调函数默认传入的Object
对象,在这里建议使用泛型来限定类型,重写readerBuilder.registerReadListener
方法
readerBuilder.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
// 将接口的泛型指定为实体类型
@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
// 指定传入的实体类型为Map<Integer, String>
Set<Integer> keySet = integerStringMap.keySet();
// 获取map的key
Iterator<Integer> iterator = keySet.iterator();
// 获取map的key的迭代器
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next + ":" + integerStringMap.get(next));
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
...
}
});
简化代码
以上的代码是该类的正常写法,但是显得过于繁重,应此可以向下面那样简化代码。
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.*;
public class Test2 {
public static void main(String[] args) {
List<Map<Integer, String>> list = new LinkedList<>();
// 定义一个集合来接收解析出来的数据
EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
.sheet()
// 指定读取的sheet,不写则读全部
.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
@Override
public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
list.add(integerStringMap);
// 指定传入的实体类型为Map<Integer, String>
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("读完所有的数据了");
}
}).doRead();
for (Map<Integer, String> map : list) {
Set<Integer> keySet = map.keySet();
Iterator<Integer> iterator = keySet.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next + ":" + map.get(next));
}
}
}
}
使用ExcelProperty注解
我们可以使用该注解来限制对象的属性对应的列
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
public class ExcelData {
@ExcelProperty(value = "姓名")
// 此注解可以指定读取的列
private String name;
@ExcelProperty(value = "班级")
private String className;
}
自定义一个对象来存储Excel
现在,已经掌握了大部分的方法,话不多说直接上代码。
// ExcelData
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
@Data
@Getter
@Setter
public class ExcelData {
@ExcelProperty(value = "姓名")
// 此注解可以指定读取的列
private String name;
@ExcelProperty(value = "班级")
private String className;
}
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.*;
public class Test2 {
public static void main(String[] args) {
List<ExcelData> list = new LinkedList<>();
// 定义一个集合来接收解析出来的数据
EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
.head(ExcelData.class)
// 根据指定的实体类去解析Excel转为LinkedHashMap
.sheet()
// 指定读取的sheet,不写则读全部
.registerReadListener(new AnalysisEventListener<ExcelData>() {
@Override
public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
list.add(excelData);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("读完所有的数据了");
}
}).doRead();
for (ExcelData excelData : list) {
System.out.println(excelData);
}
}
}
写文件
使用EasyExcel.write()
来写入文件。
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import java.util.*;
public class Test2 {
public static void main(String[] args) {
List<ExcelData> dataList = parseData();
// 读取的数据,拿来写
EasyExcel.write("E:\\测试写入副本.xlsx")
.head(ExcelData.class)
.excelType(ExcelTypeEnum.XLSX)
.sheet("测试表")
.doWrite(dataList);
}
/* 将读取的数据再次利用来写文件 */
public static List<ExcelData> parseData(){
List<ExcelData> list = new LinkedList<>();
// 定义一个集合来接收解析出来的数据
EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
.head(ExcelData.class)
// 根据指定的实体类去解析Excel转为LinkedHashMap
.sheet()
// 指定读取的sheet,不写则读全部
.registerReadListener(new AnalysisEventListener<ExcelData>() {
@Override
public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
list.add(excelData);
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
System.out.println("读完所有的数据了");
}
}).doRead();
return list;
}
}