添加 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 "";
}
}
}
代码解释:
try-with-resources:FileInputStream和Workbook都实现了AutoCloseable接口,使用try-with-resources可以确保它们在使用后被自动关闭,避免资源泄漏。WorkbookFactory.create(fis):这是一个非常方便的工具类,它会自动检测文件流是.xls还是.xlsx格式,并创建对应的HSSFWorkbook或XSSFWorkbook对象,无需我们手动判断。sheet.getSheetAt(0):获取文件中的第一个工作表(索引从0开始)。sheet.getLastRowNum():获取最后一行的索引,我们通常从1开始循环,因为第0行是表头。row.getCell(0):获取指定列索引的单元格(索引也从0开始)。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文件的简单任务。
- 优点:非常轻量,API 简单,只支持
| 库名 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| Apache POI | 功能最强大,最全面,社区庞大,支持所有 Excel 版本 | 内存占用较高,处理超大文件时可能OOM | 通用首选,功能需求复杂的场景 |
| EasyExcel | 性能好,内存占用低,API 简洁 | 功能不如 POI 全面,社区较小 | 处理大文件,对性能和内存敏感的场景 |
| JXL | 轻量,API 简单 | 已停止更新,仅支持 .xls |
处理旧版、简单的 Excel 文件 |
对于大多数项目,从 Apache POI 开始是最佳选择,如果你的应用需要处理非常大的 Excel 文件,并且遇到了性能瓶颈,那么可以转向 EasyExcel。
