杰瑞科技汇

Java如何导入Excel表格数据?

添加 Apache POI 依赖

你需要在你的项目中添加 Apache POI 的依赖,如果你使用的是 Maven,请在 pom.xml 文件中添加以下依赖:

<!-- 核心库 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version> <!-- 建议使用较新版本 -->
</dependency>
<!-- 用于处理 .xlsx 格式 (Office 2007及以后) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.3</version>
</dependency>
<!-- 用于处理 .xls 格式 (Office 97-2003) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.3</version>
</dependency>

如果你使用的是 Gradle,在 build.gradle 文件中添加:

implementation 'org.apache.poi:poi:5.2.3'
implementation 'org.apache.poi:poi-ooxml:5.2.3'

核心概念

在开始编码前,需要了解几个核心概念:

  • Workbook (工作簿):代表一个 Excel 文件,对于 .xls 格式,使用 HSSFWorkbook;对于 .xlsx 格式,使用 XSSFWorkbook
  • Sheet (工作表):代表 Excel 文件中的一个工作表,"Sheet1"。
  • Row (行):代表工作表中的一行。
  • Cell (单元格):代表行中的一个单元格,存储具体的数据。

完整代码示例:读取 Excel 文件

下面是一个完整的 Java 类,它演示了如何读取一个 Excel 文件(支持 .xls.xlsx),并将其内容打印到控制台。

假设我们有一个名为 students.xlsx 的文件,内容如下:

姓名 年龄 班级
张三 20 一班
李四 21 二班
王五 22 一班

ExcelReader.java

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ExcelReader {
    public static void main(String[] args) {
        // Excel 文件路径
        String excelFilePath = "students.xlsx"; // 或者 "students.xls"
        try (FileInputStream fis = new FileInputStream(new File(excelFilePath));
             Workbook workbook = WorkbookFactory.create(fis)) {
            // 1. 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            // 2. 遍历每一行 (从第一行开始,跳过表头)
            // sheet.getPhysicalNumberOfRows() 获取有数据的行数
            // sheet.getLastRowNum() 获取最后一行的索引
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue; // 跳过空行
                }
                // 3. 遍历每一列
                // 假设我们有3列:姓名、年龄、班级
                String name = getCellValueAsString(row.getCell(0));
                String age = getCellValueAsString(row.getCell(1));
                String className = getCellValueAsString(row.getCell(2));
                System.out.println("姓名: " + name + ", 年龄: " + age + ", 班级: " + className);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 将单元格的值转换为字符串
     * @param cell 单元格对象
     * @return 单元格的字符串值
     */
    private static String getCellValueAsString(Cell cell) {
        if (cell == null) {
            return "";
        }
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                // 处理数字类型,可能是整数也可能是小数
                if (DateUtil.isCellDateFormatted(cell)) {
                    // 如果是日期格式
                    return cell.getDateCellValue().toString();
                } else {
                    // 如果是纯数字
                    return String.valueOf((int) cell.getNumericCellValue()); // 直接转整数,避免 .0
                    // 或者使用 Double.toString(cell.getNumericCellValue()) 保留小数
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                // 如果是公式,计算公式的值
                return cell.getCellFormula();
            case BLANK:
                return "";
            default:
                return "";
        }
    }
}

代码解释:

  1. try-with-resourcesFileInputStreamWorkbook 都实现了 AutoCloseable 接口,使用 try-with-resources 可以确保它们在使用后被自动关闭,避免资源泄漏。
  2. WorkbookFactory.create(fis):这是一个非常方便的工具类,它会自动检测文件流是 .xls 还是 .xlsx 格式,并创建对应的 HSSFWorkbookXSSFWorkbook 对象,无需我们手动判断。
  3. sheet.getSheetAt(0):获取文件中的第一个工作表(索引从0开始)。
  4. sheet.getLastRowNum():获取最后一行的索引,我们通常从 1 开始循环,因为第 0 行是表头。
  5. row.getCell(0):获取指定列索引的单元格(索引也从0开始)。
  6. getCellValueAsString 方法:这是处理不同类型单元格数据的关键,Excel 单元格有多种类型(字符串、数字、布尔值、公式等),我们需要根据 cell.getCellType() 来分别处理,最后统一转换为字符串。

处理更复杂的情况

1 读取大文件(避免内存溢出)

对于非常大的 Excel 文件(例如几百MB或上GB),一次性将整个文件加载到内存中可能会导致 OutOfMemoryError,这时可以使用 SXSSFWorkbook(流式 API),它只会保留一部分数据在内存中,其余数据会临时写入硬盘。

BigExcelReader.java (示例)

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
public class BigExcelReader {
    public static void main(String[] args) {
        String excelFilePath = "very_large_file.xlsx";
        // SXSSFWorkbook 的参数 100 表示在内存中保留100行,其余写入临时文件
        try (Workbook workbook = new SXSSFWorkbook(new XSSFWorkbook(new FileInputStream(excelFilePath)))) {
            Sheet sheet = workbook.getSheetAt(0);
            // ... 读取逻辑与之前类似 ...
            // 注意:SXSSFWorkbook 不支持所有功能,比如单元格样式等。
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 重要:在读取完成后,必须清理临时文件
            if (workbook instanceof SXSSFWorkbook) {
                ((SXSSFWorkbook) workbook).dispose();
            }
        }
    }
}

2 将数据存入数据库(实际应用场景)

读取 Excel 的最终目的通常是处理数据,比如存入数据库,下面是一个结合 JDBC 的示例。

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
// ... (前面的 ExcelReader 代码部分) ...
public class ExcelToDatabase {
    public static void main(String[] args) {
        String excelFilePath = "students.xlsx";
        // 数据库连接信息 (请替换为你自己的)
        String dbUrl = "jdbc:mysql://localhost:3306/testdb";
        String dbUser = "root";
        String dbPassword = "password";
        String sql = "INSERT INTO students (name, age, class_name) VALUES (?, ?, ?)";
        try (Connection conn = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
             PreparedStatement pstmt = conn.prepareStatement(sql);
             FileInputStream fis = new FileInputStream(new File(excelFilePath));
             Workbook workbook = WorkbookFactory.create(fis)) {
            Sheet sheet = workbook.getSheetAt(0);
            for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                if (row == null) continue;
                // 设置 SQL 参数
                pstmt.setString(1, getCellValueAsString(row.getCell(0)));
                pstmt.setInt(2, Integer.parseInt(getCellValueAsString(row.getCell(1))));
                pstmt.setString(3, getCellValueAsString(row.getCell(2)));
                // 执行插入
                pstmt.addBatch();
            }
            // 一次性执行所有批处理
            int[] result = pstmt.executeBatch();
            System.out.println("成功插入 " + result.length + " 条数据。");
        } catch (IOException | SQLException e) {
            e.printStackTrace();
        }
    }
    // ... (与前面相同的 getCellValueAsString 方法) ...
}

其他选择

除了 Apache POI,还有一些其他库,各有特点:

  • EasyExcel (阿里巴巴)

    • 优点:API 更简洁,性能更好,内存占用极低(底层使用 SAX 模式解析),对大文件支持非常好,是目前国内非常流行的选择。
    • 缺点:社区和生态相比 POI 稍小。
    • 适用场景:对性能和内存有高要求的项目,特别是处理超大 Excel 文件。
  • JXL (Java Excel API)

    • 优点:非常轻量,API 简单,只支持 .xls 格式。
    • 缺点:已经停止更新多年,不支持 .xlsx 格式,功能有限。
    • 适用场景:处理旧版 .xls 文件的简单任务。
库名 优点 缺点 推荐场景
Apache POI 功能最强大,最全面,社区庞大,支持所有 Excel 版本 内存占用较高,处理超大文件时可能OOM 通用首选,功能需求复杂的场景
EasyExcel 性能好,内存占用低,API 简洁 功能不如 POI 全面,社区较小 处理大文件,对性能和内存敏感的场景
JXL 轻量,API 简单 已停止更新,仅支持 .xls 处理旧版、简单的 Excel 文件

对于大多数项目,从 Apache POI 开始是最佳选择,如果你的应用需要处理非常大的 Excel 文件,并且遇到了性能瓶颈,那么可以转向 EasyExcel

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