【Java实现 通过Easy Excel完成对excel文本数据的读写】
Java实现 通过Easy Excel完成对excel文本数据的读写
- EasyExcel 官网概述
- 1. 准备工作
- 1.1 添加依赖
- 1.2 创建模型类
- 1.3 最简单的读的监听器(参考官网)
- 2. 读取Excel文件
- 2.1 核心原理
- 2.2 基础读取
- 2.3 读多个sheet
- 2.4 错误处理
- 3. 写入Excel文件
- 3.1 基础写入
EasyExcel 官网概述
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。
easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。
1. 准备工作
1.1 添加依赖
<dependency>
<groupId>com.alibaba.easyexcel</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.3</version>
</dependency>
查看最新版本
1.2 创建模型类
Excel 中的数据需要映射到 Java 对象,先创建一个模型类。
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Getter;
import lombok.Setter;
/**
* @author: gaokelai
* @date: 2025/1/23
*/
@Getter
@Setter
public class Weather {
/**
* 地区
*/
@ExcelProperty("地区")
private String cityName;
/**
* 时间
*/
@ExcelProperty("时间")
private String fxTime;
/**
* 天气
*/
@ExcelProperty("天气")
private String text;
/**
* 温度℃
*/
@ExcelProperty("温度℃")
private String temp;
/**
* 降水量
*/
@ExcelProperty("降水量")
private String precip;
/**
* 风向
*/
@ExcelProperty("风向")
private String windDir;
/**
* 风力
*/
@ExcelProperty("风力")
private String windScale;
/**
* 风速
*/
@ExcelProperty("风速")
private String windSpeed;
/**
* 气压
*/
@ExcelProperty("气压")
private String pressure;
/**
* 湿度
*/
@ExcelProperty("湿度")
private String humidity;
}
1.3 最简单的读的监听器(参考官网)
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;
/**
* 缓存的数据
*/
private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoDAO.save(cachedDataList);
log.info("存储数据库成功!");
}
}
2. 读取Excel文件
2.1 核心原理
EasyExcel 使用了 SAX 解析器来解析 Excel 文件,这是一种事件驱动的解析方式,能够逐行读取数据而不需要一次性加载整个文档到内存中,同时通过流式读取减少了内存占用,提高了性能。
2.2 基础读取
基础读取是最简单的读取方式,适合小文件或测试环境:
/**
* 最简单的读
* <p>
* 1. 创建excel对应的实体对象 Weather
* <p>
* 2. 直接读即可
*/
public void basicRead() {
String fileName = "E:\\逐小时天气\\BeiJing-2024-01.xlsx";
// 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行
// 具体需要返回多少行可以在`PageReadListener`的构造函数设置
EasyExcel.read(fileName, Weather.class, new PageReadListener<Weather>(dataList -> {
for (Weather weather: dataList) {
System.out.println(JSON.toJSONString(weather));
}
})).sheet().doRead();
}
}
2.3 读多个sheet
/**
* 读多个或者全部sheet,这里注意一个sheet不能读取多次,多次读取需要重新读取文件
* <p>
* 1. 创建excel对应的实体对象 Weather
* <p>
* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器 DemoDataListener
* <p>
* 3. 直接读即可
*/
public void repeatedRead() {
String fileName = "E:\\逐小时天气\\BeiJing-2024-01-2024-10.xlsx";
// 读取全部sheet
// 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
EasyExcel.read(fileName, Weather.class, new DemoDataListener()).doReadAll();
// 读取部分sheet
fileName = "E:\\逐小时天气\\BeiJing-2024-01-2024-10.xlsx";
try (ExcelReader excelReader = EasyExcel.read(fileName).build()) {
// 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
ReadSheet readSheet1 =
EasyExcel.readSheet(0).head(Weather.class).registerReadListener(new DemoDataListener()).build();
ReadSheet readSheet2 =
EasyExcel.readSheet(1).head(Weather.class).registerReadListener(new DemoDataListener()).build();
// 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
excelReader.read(readSheet1, readSheet2);
}
}
2.4 错误处理
当进行读取操作时,应该考虑可能出现的异常情况,并适当处理它们:
try {
basicRead();
//repeatedRead();
} catch (Exception e) {
e.printStackTrace();
// 处理异常逻辑
}
3. 写入Excel文件
3.1 基础写入
public void basicWrite() {
String fileName = "E:\\逐小时天气\\newDataDemo.xlsx";
// 创建要写入的数据列表
List<Weather> list = new ArrayList<>();
list.add(new Weather("北京", "2025/01/23 08:00:00", "晴","18","0","东北风","1","3","996","87"));
list.add(new Weather("北京", "2025/01/23 09:00:00", "晴","18","0","东北风","1","3","996","87"));
list.add(new Weather("北京", "2025/01/23 10:00:00", "晴","18","0","东北风","1","3","996","87"));
// 写入 Excel 文件
EasyExcel.write(fileName, UserData.class).sheet("天气信息").doWrite(list);
}
高级写法及其他写入Excel技巧参考官网 Easy Excel