EasyExcel 是阿里巴巴开源的 Java Excel 处理工具,以事件驱动模式为核心,支持大文件低内存读取、灵活的数据映射及丰富的配置选项,是 Java 生态中处理 Excel 文件的高效选择。
一、前置准备:添加 EasyExcel 依赖
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.2.1</version> <!-- 版本号根据实际情况调整 -->
</dependency>
        二、基础读取流程:从文件到内存
EasyExcel 读取 Excel 的核心流程可分为创建读取器→配置参数→注册监听器→执行读取四步:
1. 创建读取器
通过 EasyExcel.read()方法创建 ExcelReaderBuilder实例,支持传入文件路径(String) 、文件对象(File) 或输入流(InputStream)
// 方式1:通过文件路径读取(自动关闭流)
ExcelReaderBuilder builder = EasyExcel.read("D:\\data\\user.xlsx");
// 方式2:通过输入流读取(需手动管理流生命周期)
InputStream inputStream = new FileInputStream("D:\\data\\user.xlsx");
ExcelReaderBuilder builder = EasyExcel.read(inputStream);
        2. 配置读取参数
通过 ExcelReaderBuilder配置读取细节,常见参数包括:
sheet :指定读取的 Sheet(可传入索引(0 开始) 、名称(如"Sheet1") 或直接调用 sheet()默认读取第一个 Sheet);•
headRowNumber:指定表头所在行(默认 0,即第一行为表头);
autoCloseStream:是否自动关闭输入流(默认 true,避免资源泄漏);
excelType :指定 Excel 类型(ExcelTypeEnum.XLS或 ExcelTypeEnum.XLSX,可自动识别)。
builder.sheet("用户数据") // 读取名为"用户数据"的Sheet
       .headRowNumber(1) // 表头在第二行
       .autoCloseStream(true); // 自动关闭流
        
3. 注册监听器
通过 registerReadListener方法注册 AnalysisEventListener实现类,用于处理读取到的数据。监听器包含两个核心方法:
invoke(T data, AnalysisContext context) :每读取一行数据时触发,data为当前行映射的对象(或 Map);
doAfterAllAnalysed(AnalysisContext context):所有数据解析完成后触发,用于收尾操作(如关闭数据库连接)。
示例1:监听器处理 Map 数据(无实体类)
builder.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
    @Override
    public void invoke(Map<Integer, String> rowData, AnalysisContext context) {
        // 打印每行数据(键为列索引,值为单元格内容)
        rowData.forEach((colIndex, value) -> 
            System.out.print(colIndex + ":" + value + "\t"));
        System.out.println();
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        System.out.println("数据读取完毕!");
    }
});
        示例2:监听器处理实体类数据(推荐)
通过实体类的 @ExcelProperty注解实现列与字段的映射,提升代码可读性:
// 实体类:定义列映射关系
@Data
public class UserData {
    @ExcelProperty("用户ID") // 列名为"用户ID"
    private Long userId;
    
    @ExcelProperty("用户名")
    private String username;
    
    @ExcelProperty("年龄")
    private Integer age;
}
// 监听器:处理实体类数据
builder.registerReadListener(new AnalysisEventListener<UserData>() {
    private final List<UserData> dataList = new ArrayList<>();
    @Override
    public void invoke(UserData userData, AnalysisContext context) {
        dataList.add(userData); // 收集数据
        if (dataList.size() >= 1000) { // 批量处理(避免内存溢出)
            saveToDatabase(dataList);
            dataList.clear();
        }
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveToDatabase(dataList); // 保存剩余数据
        System.out.println("数据读取完毕,共 " + dataList.size() + " 条!");
    }
    private void saveToDatabase(List<UserData> list) {
        // 批量保存到数据库的逻辑(如MyBatis、JPA)
        System.out.println("批量保存 " + list.size() + " 条数据");
    }
});
        4. 执行读取
调用 doRead()方法启动读取流程(同步执行):
builder.doRead(); // 同步读取(阻塞直到完成)
// 或 builder.doReadSync()(效果相同)
        三、进阶用法:灵活配置与优化
1. 动态指定 Sheet
通过 sheet(int index)或 sheet(String name)动态选择 Sheet,例如读取第二个 Sheet
EasyExcel.read("D:\\data\\user.xlsx", UserData.class, listener).sheet(1).doRead();
        2. 自定义表头行
若 Excel 表头不在第一行,可通过 headRowNumber指定:
builder.headRowNumber(2); // 表头在第三行
        3. 处理额外信息(合并单元格、批注等)
重写监听器的 extra(CellExtra extra, AnalysisContext context)方法,获取合并单元格、批注等额外信息:
@Override
public void extra(CellExtra extra, AnalysisContext context) {
    if (extra.getType() == CellExtraTypeEnum.MERGE) {
        System.out.println("合并单元格:起始行 " + extra.getFirstRowIndex() + 
                          ",起始列 " + extra.getFirstColumnIndex() + 
                          ",结束行 " + extra.getLastRowIndex() + 
                          ",结束列 " + extra.getLastColumnIndex());
    }
}
        4. 批量处理数据(避免内存溢出)
通过监听器收集数据并批量处理(如批量插入数据库),减少内存占用
private static final int BATCH_SIZE = 1000;
private List<UserData> batchList = new ArrayList<>();
@Override
public void invoke(UserData userData, AnalysisContext context) {
    batchList.add(userData);
    if (batchList.size() >= BATCH_SIZE) {
        saveBatch(batchList);
        batchList.clear();
    }
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
    if (!batchList.isEmpty()) {
        saveBatch(batchList);
    }
}
        四、注意事项
内存优化:务必通过批量处理(如每 1000 条保存一次)避免内存溢出,尤其处理大文件时;•
异常处理 :监听器中的 invoke方法抛出异常会终止读取,建议捕获异常并记录日志,而非直接抛出;
流管理 :若未设置 autoCloseStream(true),需手动关闭输入流,防止资源泄漏;•
版本兼容:EasyExcel 3.x 版本对 API 进行了优化,建议升级至最新稳定版。
通过以上步骤,可实现 EasyExcel 对 Excel 文件的高效读取,满足不同场景下的数据处理需求
五、无实体类读取excel文件教程
package com.example.util;
import com.alibaba.excel.EasyExcel;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class EasyExcelUtil {
    static  List<Map<Integer,String>>   readExelFile( InputStream  fileInputStream){
        List<Map<Integer, String>> dataList=new ArrayList<>();
        try (InputStream inputStream =fileInputStream) {
            // 同步读取 Excel 文件(返回 List<Map<Integer, String>>)
           dataList = EasyExcel.read(inputStream, null, null)
                    .sheet() // 读取默认 Sheet
                    .headRowNumber(1) // 表头行索引
                    .doReadSync(); // 同步读取
            // 处理返回的数据
            for (Map<Integer, String> row : dataList) {
                System.out.println("当前行数据:" + row);
                // 示例:打印第一列的值
                System.out.println("第一列: " + row.get(0));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataList;
    }
}
        测代码
 InputStream inputStream = new FileInputStream("D:\\temp\\1.xlsx");
        EasyExcelUtil.readExelFile(inputStream);