下面我将为你提供一个详细的、从入门到实践的指南,包括:

- 环境准备:如何添加 POI 依赖。
- 核心概念:了解
XSSFWorkbook和HSSFWorkbook的区别。 - 基础读取:读取
.xlsx和.xls文件的基本步骤。 - 完整代码示例:包含处理不同数据类型和异常处理的完整可运行代码。
- 进阶技巧:读取公式、日期、样式等。
环境准备 (Maven)
如果你使用 Maven,在 pom.xml 文件中添加 POI 的依赖。强烈推荐使用 poi-ooxml,因为它同时支持旧版 .xls 和新版 .xlsx 格式。
<dependencies>
<!-- Apache POI 核心库 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version> <!-- 建议使用最新稳定版 -->
</dependency>
<!-- 用于处理 Office Open XML 格式(.xlsx)的库 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version> <!-- 建议使用最新稳定版 -->
</dependency>
<!-- 如果需要处理 .xlsx 中的图表等,可能需要这个 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-lite</artifactId>
<version>5.2.5</version>
</dependency>
</dependencies>
核心概念:XSSFWorkbook vs HSSFWorkbook
在开始编码前,必须了解 POI 处理两种不同 Excel 格式的核心类:
| 特性 | HSSFWorkbook | XSSFWorkbook |
|---|---|---|
| 支持的文件格式 | .xls (Excel 97-2003) |
.xlsx (Excel 2007 及以后) |
| 底层技术 | 基于 BIFF (Binary Interchange File Format) | 基于 OOXML (Office Open XML),本质是 ZIP 包 |
| 内存消耗 | 高,所有数据都会加载到内存中。 | 较低,支持 SAX 模式(XSSF 和 SAX)进行事件驱动解析,内存占用小,适合大文件。 |
| POI 模块 | poi |
poi-ooxml |
- 如果你的文件是
.xls,使用HSSFWorkbook。 - 如果你的文件是
.xlsx,使用XSSFWorkbook。 - 为了代码的通用性和健壮性,你可以通过文件后缀名来决定使用哪个类。
基础读取步骤
读取 Excel 文件的基本流程可以概括为以下四步:

- 加载文件:使用
FileInputStream读取 Excel 文件到输入流。 - 创建工作簿对象:根据文件类型,创建
XSSFWorkbook或HSSFWorkbook对象。 - 获取工作表:通过工作簿对象,按名称或索引获取
Sheet对象。 - 遍历行和单元格:通过
Sheet对象获取Row对象,再通过Row对象获取Cell对象,最后读取单元格的值。
完整代码示例
下面是一个完整的 Java 类,它可以读取一个 .xlsx 文件,并打印出所有内容,代码中包含了详细的注释和异常处理。
示例 Excel 文件 (data.xlsx)
| 姓名 | 年龄 | 入职日期 | 薪资 | 是否在职 |
|---|---|---|---|---|
| 张三 | 28 | 2025-05-20 | 50 | true |
| 李四 | 35 | 2025-11-01 | 00 | false |
| 王五 | 22 | 2025-03-15 | 00 | true |
ExcelReader.java
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExcelReader {
public static void main(String[] args) {
// 1. 定义要读取的文件路径
String excelFilePath = "path/to/your/data.xlsx"; // <--- 请替换为你的文件路径
try ( // 使用 try-with-resources 确保 FileInputStream 和 Workbook 自动关闭
FileInputStream fis = new FileInputStream(excelFilePath);
// 2. 根据文件类型创建 Workbook 对象
// .xlsx 文件使用 XSSFWorkbook
Workbook workbook = new XSSFWorkbook(fis)
) {
// 3. 获取第一个工作表 (Sheet)
// 也可以通过名称获取:Sheet sheet = workbook.getSheet("员工信息");
Sheet sheet = workbook.getSheetAt(0);
// 定义一个日期格式化器,用于处理日期单元格
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("开始读取 Excel 文件内容...");
// 4. 遍历工作表中的每一行
// 从第一行开始,跳过表头 (sheet.getFirstRowNum() 是 0)
for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
Row row = sheet.getRow(rowNum);
// 如果行是空的,则跳过
if (row == null) {
continue;
}
// 遍历行中的每一个单元格
for (int cellNum = 0; cellNum < row.getLastCellNum(); cellNum++) {
Cell cell = row.getCell(cellNum);
// 如果单元格是空的,则跳过
if (cell == null) {
System.out.print("\t"); // 保持对齐
continue;
}
// 5. 根据单元格类型获取值
String cellValue = getCellValueAsString(cell, dateFormat);
System.out.print(cellValue + "\t"); // 用制表符隔开
}
System.out.println(); // 每行结束后换行
}
System.out.println("Excel 文件读取完成!");
} catch (IOException e) {
System.err.println("读取 Excel 文件时发生错误: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 将 Cell 对象的值转换为 String
* @param cell 单元格对象
* @param dateFormat 日期格式化器
* @return 单元格值的字符串表示
*/
private static String getCellValueAsString(Cell cell, SimpleDateFormat dateFormat) {
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
// 处理日期
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
return dateFormat.format(date);
} else {
// 处理普通数字
// 为了防止数字过长被科学计数法,或者变成.0,可以这样处理
double numericValue = cell.getNumericCellValue();
if (numericValue == (long) numericValue) {
return String.valueOf((long) numericValue);
} else {
return String.valueOf(numericValue);
}
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
// 如果单元格是公式,可以获取公式的计算结果
// 注意:需要先 workbook.getCreationHelper().createFormulaEvaluator().evaluateFormulaCell(cell)
// 然后根据返回的 CellValue 类型来取值
// 这里简单处理,直接获取公式的字符串
return cell.getCellFormula();
case BLANK:
return "";
default:
return "";
}
}
}
进阶技巧
1 读取公式
要读取单元格中公式的计算结果,而不是公式本身,你需要使用 FormulaEvaluator。
// 在创建 Workbook 后,获取 FormulaEvaluator
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
// 在遍历单元格时
Cell cell = row.getCell(cellNum);
if (cell.getCellType() == CellType.FORMULA) {
// 评估公式,获取结果
CellValue evaluatedValue = evaluator.evaluate(cell);
switch (evaluatedValue.getCellType()) {
case STRING:
System.out.print(evaluatedValue.getStringValue() + "\t");
break;
case NUMERIC:
System.out.print(evaluatedValue.getNumberValue() + "\t");
break;
// ... 其他类型
}
}
2 读取日期
如上面的完整代码所示,使用 DateUtil.isCellDateFormatted(cell) 来判断一个数字单元格是否是日期格式,如果是,则用 cell.getDateCellValue() 获取 Date 对象,再用 SimpleDateFormat 进行格式化。
3 读取样式(字体、颜色、背景等)
读取样式信息稍微复杂一些,因为它涉及到多个对象。

// 假设 cell 已经存在
CellStyle cellStyle = cell.getCellStyle();
// 1. 获取字体
Font font = workbook.getFontAt(cellStyle.getFontIndex());
System.out.println("字体名称: " + font.getFontName());
System.out.println("字体大小: " + font.getFontHeightInPoints());
System.out.println("是否加粗: " + font.getBold());
// 2. 获取背景颜色
// 注意:颜色索引需要从工作簿的调色板中获取
short bgColorIndex = cellStyle.getFillForegroundColorIndex();
XSSFColor xssfColor = (XSSFColor) workbook.getCellStyleAt(cellStyle.getIndex()).getFillForegroundColorColor();
if (xssfColor != null) {
byte[] rgb = xssfColor.getRGB();
System.out.println("背景颜色 RGB: " + String.format("%02X%02X%02X", rgb[0], rgb[1], rgb[2]));
}
// 3. 获取对齐方式
System.out.println("水平对齐: " + cellStyle.getAlignment());
System.out.println("垂直对齐: " + cellStyle.getVerticalAlignment());
4 处理大文件(SAX 模式)
对于非常大的 .xlsx 文件(几百MB甚至上GB),使用 XSSFWorkbook 会耗尽所有内存,这时必须使用 SAX 模式(事件驱动模型)。
它不会一次性将整个文件加载到内存,而是像 XML 解析一样,逐行读取事件(如:开始行、结束行、单元格数据等)。
你需要使用 XSSF 和 SAX 的组合类,org.apache.poi.xssf.eventusermodel.XSSFReader 和 org.apache.poi.xssf.eventusermodel.XSSFReader.SheetIterator。
这个模型比 DOM 模型(XSSFWorkbook)复杂,但内存效率极高,具体实现可以参考 POI 官方文档或相关教程。
| 任务 | 关键类/方法 | 备注 |
|---|---|---|
| 加载文件 | new FileInputStream(path) |
使用 try-with-resources |
| 创建工作簿 | new XSSFWorkbook(fis) (.xlsx) 或 new HSSFWorkbook(fis) (.xls) |
推荐使用 poi-ooxml |
| 获取工作表 | workbook.getSheetAt(0) 或 workbook.getSheet("name") |
索引从0开始 |
| 获取行 | sheet.getRow(i) |
i 是行号 |
| 获取单元格 | row.getCell(j) |
j 是列号 |
| 获取单元格值 | cell.getStringCellValue(), cell.getNumericCellValue() 等 |
必须先用 getCellType() 判断类型 |
| 处理日期 | DateUtil.isCellDateFormatted(cell) + cell.getDateCellValue() |
|
| 处理公式 | workbook.getCreationHelper().createFormulaEvaluator().evaluate(cell) |
|
| 处理大文件 | XSSFReader + SAX 事件驱动 |
内存效率高,代码复杂 |
希望这份详细的指南能帮助你顺利地使用 Java POI 读取 Excel 文件!
