杰瑞科技汇

Java读取Excel数据的方法有哪些?

三种主流方案对比

特性 Apache POI EasyExcel JXL
维护方 Apache 软件基金会(顶级项目) 阿里巴巴(开源) JavaExcel (已停止更新)
优势 功能最全面,支持所有 Office 格式(.xls, .xlsx, .docx等) 性能极高,内存占用极低,尤其适合处理大文件 简单易用,轻量级
劣势 对于大文件(如 .xlsx),内存消耗巨大,容易导致 OOM(内存溢出) 相对较新,社区和功能生态不如 POI 完善 仅支持 .xls 格式,不支持 .xlsx,已不推荐使用
适用场景 需要处理多种 Office 格式,或对功能有复杂要求 专门为大数据量 Excel 设计,是处理 .xlsx 文件的首选 遗留系统维护,或处理非常小的、仅 .xls 格式的文件

总结建议:

Java读取Excel数据的方法有哪些?-图1
(图片来源网络,侵删)
  • 新项目、处理 .xlsx 文件(尤其是大文件)强烈推荐使用 EasyExcel
  • 需要处理 .xls 文件,或功能复杂:使用 Apache POI
  • 不推荐使用 JXL,除非有特殊的历史遗留原因。

使用 Apache POI (功能全面)

Apache POI 是 Java 操作 Office 文件的事实标准。

添加 Maven 依赖

你需要根据你处理的 Excel 版本(.xls.xlsx)来添加不同的依赖。

<!-- 对于 .xls 格式 (HSSFWorkbook) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>
<!-- 对于 .xlsx 格式 (XSSFWorkbook) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
<!-- 为了支持 XML 解析,还需要这个依赖 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-lite</artifactId>
    <version>5.2.3</version>
</dependency>

代码示例 (读取 .xlsx 文件)

这里我们读取一个名为 user_data.xlsx 的文件,它有三列:ID, 姓名, 年龄。

Excel 文件内容 (user_data.xlsx): | ID | 姓名 | 年龄 | | :-- | :--- | :--- | | 1 | 张三 | 25 | | 2 | 李四 | 30 | | 3 | 王五 | 28 |

Java读取Excel数据的方法有哪些?-图2
(图片来源网络,侵删)

Java 代码:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class PoiExcelReader {
    public static void main(String[] args) {
        String filePath = "user_data.xlsx"; // 文件路径
        List<User> userList = readExcelWithPoi(filePath);
        // 打印读取结果
        for (User user : userList) {
            System.out.println(user);
        }
    }
    public static List<User> readExcelWithPoi(String filePath) {
        List<User> userList = new ArrayList<>();
        FileInputStream fis = null;
        Workbook workbook = null;
        try {
            // 1. 获取文件输入流
            fis = new FileInputStream(filePath);
            // 2. 根据文件格式创建 Workbook 对象
            // 对于 .xlsx 文件,使用 XSSFWorkbook
            // 对于 .xls 文件,使用 HSSFWorkbook
            workbook = new XSSFWorkbook(fis);
            // 3. 获取第一个工作表 (Sheet)
            Sheet sheet = workbook.getSheetAt(0);
            // 4. 遍历每一行 (从第二行开始,跳过表头)
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue; // 跳过空行
                }
                // 5. 获取单元格的值
                // 注意:getCell() 的第二个参数 CellType.BLANK 表示如果单元格为空,则返回一个空白单元格,而不是 null
                Cell idCell = row.getCell(0, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                Cell nameCell = row.getCell(1, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                Cell ageCell = row.getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                // 6. 处理不同类型的单元格数据
                // getCellType() 获取单元格类型,然后根据类型转换
                long id = (long) idCell.getNumericCellValue();
                String name = nameCell.getStringCellValue();
                int age = (int) ageCell.getNumericCellValue();
                // 7. 将数据封装到对象中
                User user = new User(id, name, age);
                userList.add(user);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 8. 关闭资源
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return userList;
    }
}
// 用于封装数据的简单实体类
class User {
    private long id;
    private String name;
    private int age;
    public User(long id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

使用 EasyExcel (高性能,推荐)

阿里巴巴开源的 EasyExcel 通过 SAX 模式(事件驱动)来解析 Excel,极大地降低了内存消耗,非常适合处理百万行级别的大数据。

添加 Maven 依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.1.1</version>
</dependency>

代码示例 (读取 .xlsx 文件)

EasyExcel 的核心是 监听器,你创建一个监听器,当 EasyExcel 读取到一行数据时,就会调用监听器中的方法。

Excel 文件内容: 与 POI 示例相同 (user_data.xlsx)。

Java读取Excel数据的方法有哪些?-图3
(图片来源网络,侵删)

Java 代码:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class EasyExcelReader {
    public static void main(String[] args) {
        String fileName = "user_data.xlsx";
        // 创建一个监听器
        ReadDataListener listener = new ReadDataListener();
        // EasyExcel 会自动关闭流,你不需要手动关闭
        EasyExcel.read(fileName, User.class, listener).sheet().doRead();
        // 从监听器中获取数据
        List<User> userList = listener.getDataList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}
/**
 * 自定义监听器
 */
class ReadDataListener extends AnalysisEventListener<User> {
    /**
     * 使用这个 list 来存储每一条数据,数据量大的话,建议使用数据库等存储方式。
     */
    private List<User> dataList = new ArrayList<>();
    @Override
    public void invoke(User user, AnalysisContext analysisContext) {
        // 每解析一行数据,就会调用一次这个方法
        System.out.println("解析到一条数据: " + user);
        dataList.add(user);
    }
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 所有数据解析完毕后调用这个方法
        System.out.println("所有数据解析完成!");
    }
    public List<User> getDataList() {
        return dataList;
    }
}
// User 类需要与 Excel 列一一对应,可以通过 @ExcelProperty 注解指定列名
class User {
    // 使用 @ExcelProperty("ID") 来指定对应的 Excel 列标题
    // 如果不写,默认按字段顺序匹配
    @com.alibaba.excel.annotation.ExcelProperty("ID")
    private Long id;
    @com.alibaba.excel.annotation.ExcelProperty("姓名")
    private String name;
    @com.alibaba.excel.annotation.ExcelProperty("年龄")
    private Integer age;
    // EasyExcel 要求有无参构造器
    public User() {
    }
    // 可以省略 getter/setter,但为了方便打印,这里加上
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

EasyExcel 的优点:

  1. 内存友好invoke 方法是逐行调用的,读完一行后,这一行的数据可以被垃圾回收,不会一直堆积在内存中。
  2. 代码简洁:无需手动创建 WorkbookSheet 对象,代码量更少。
  3. 功能强大:支持将数据直接读入数据库(AnalysisEventListener 有现成的模板),支持复杂的表头处理等。

使用 JXL (简单过时)

JXL 是一个轻量级的库,非常简单,但已停止更新多年,不支持 .xlsx 格式。

添加 Maven 依赖

JXL 没有官方的 Maven 仓库,通常需要手动下载 JAR 包并安装到本地仓库,或者直接在项目中引入 JAR。

<!-- 如果你将 jxl.jar 放在了项目的 lib 目录下 -->
<dependency>
    <groupId>net.sourceforge.jexcelapi</groupId>
    <artifactId>jxl</artifactId>
    <version>2.6.12</version>
</dependency>

代码示例 (仅支持 .xls)

import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class JxlExcelReader {
    public static void main(String[] args) {
        String filePath = "user_data.xls"; // 注意:必须是 .xls 文件
        List<User> userList = readExcelWithJxl(filePath);
        for (User user : userList) {
            System.out.println(user);
        }
    }
    public static List<User> readExcelWithJxl(String filePath) {
        List<User> userList = new ArrayList<>();
        Workbook workbook = null;
        try {
            // 1. 创建 Workbook 对象
            workbook = Workbook.getWorkbook(new File(filePath));
            // 2. 获取第一个工作表
            Sheet sheet = workbook.getSheet(0);
            // 3. 遍历行 (从第二行开始)
            for (int i = 1; i < sheet.getRows(); i++) {
                // 4. 遍历列
                long id = Long.parseLong(sheet.getCell(0, i).getContents());
                String name = sheet.getCell(1, i).getContents();
                int age = Integer.parseInt(sheet.getCell(2, i).getContents());
                User user = new User(id, name, age);
                userList.add(user);
            }
        } catch (IOException | BiffException e) {
            e.printStackTrace();
        } finally {
            // 5. 关闭 Workbook
            if (workbook != null) {
                workbook.close();
            }
        }
        return userList;
    }
}
// User 类与前面相同

总结与最终建议

易用性 性能 功能 推荐度
EasyExcel 极高 良好 ⭐⭐⭐⭐⭐ (首选)
Apache POI 中等 中等 (大文件差) 最全 ⭐⭐⭐⭐ (备选)
JXL 中等 基础 ⭐ (不推荐)

对于任何新的 Java 项目,强烈建议你从 EasyExcel 开始,它在处理现代 Excel 格式(.xlsx)方面,无论是性能还是开发效率,都远超传统的 Apache POI,只有当你需要兼容旧版 .xls 文件或遇到 POI 独有的复杂功能时,才考虑使用 POI。

分享:
扫描分享到社交APP
上一篇
下一篇