【Java实现 通过Easy Excel完成对excel文本数据的读写】

Java实现 通过Easy Excel完成对excel文本数据的读写

  • [EasyExcel 官网概述](#EasyExcel 官网概述)
  • [1. 准备工作](#1. 准备工作)
    • [1.1 添加依赖](#1.1 添加依赖)
    • [1.2 创建模型类](#1.2 创建模型类)
    • [1.3 最简单的读的监听器(参考官网)](#1.3 最简单的读的监听器(参考官网))
  • [2. 读取Excel文件](#2. 读取Excel文件)
    • [2.1 核心原理](#2.1 核心原理)
    • [2.2 基础读取](#2.2 基础读取)
    • [2.3 读多个sheet](#2.3 读多个sheet)
    • [2.4 错误处理](#2.4 错误处理)
  • [3. 写入Excel文件](#3. 写入Excel文件)
    • [3.1 基础写入](#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 添加依赖

xml 复制代码
<dependency>
    <groupId>com.alibaba.easyexcel</groupId>
    <artifactId>easyexcel</artifactId>
    <version>4.0.3</version> 
</dependency>

查看最新版本

1.2 创建模型类

Excel 中的数据需要映射到 Java 对象,先创建一个模型类。

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 最简单的读的监听器(参考官网)

java 复制代码
// 有个很重要的点 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 基础读取

基础读取是最简单的读取方式,适合小文件或测试环境:

java 复制代码
	/**
     * 最简单的读
     * <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

java 复制代码
    /**
     * 读多个或者全部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 错误处理

当进行读取操作时,应该考虑可能出现的异常情况,并适当处理它们:

java 复制代码
	try {
	    basicRead();
	    //repeatedRead();
	} catch (Exception e) {
	    e.printStackTrace();
	    // 处理异常逻辑
	}

3. 写入Excel文件

3.1 基础写入

java 复制代码
	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

相关推荐
组合缺一1 小时前
Solon Cloud Gateway 开发:Helloword
java·gateway·solon
奕辰杰4 小时前
关于使用微服务的注意要点总结
java·微服务·架构
m0_748230214 小时前
适用于IntelliJ IDEA 2024.1.2部署Tomcat的完整方法,以及笔者踩的坑,避免高血压,保姆级教程
java·tomcat·intellij-idea
六毛的毛5 小时前
java后端之登录认证
java·开发语言·python
customer086 小时前
【开源免费】基于SpringBoot+Vue.JS校园失物招领系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
中國移动丶移不动7 小时前
Java 反射与动态代理:实践中的应用与陷阱
java·spring boot·后端·spring·mybatis·hibernate
DEARM LINER7 小时前
RabbitMQ 死信队列
java·rabbitmq·java-rabbitmq
组合缺一7 小时前
drools 规则引擎和 solon-flow 哪个好?solon-flow 简明教程
java·solon·flow·drools
曲奇是块小饼干_8 小时前
leetcode刷题记录(九十)——74. 搜索二维矩阵
java·数据结构·算法·leetcode·职场和发展·矩阵
测试19988 小时前
Pytest+Allure+Excel接口自动化测试框架实战
自动化测试·软件测试·python·测试工具·职场和发展·excel·pytest