使用 Apache POI 读取 Excel 文件是 Java 开发中非常常见的场景,Apache POI 提供了两套主要的 API 来处理不同版本的 Excel 文件:
- HSSF:用于处理旧版 Excel 格式(
.xls,Excel 97-2003)。 - XSSF:用于处理新版 Excel 格式(
.xlsx,Excel 2007 及以后)。
为了兼容两种格式,通常建议使用 WorkbookFactory 自动识别文件类型。
✅ 推荐方式:使用 WorkbookFactory 自动识别格式
以下是一个完整的示例,展示如何读取 .xls 和 .xlsx 文件,并遍历所有单元格数据。
添加 Maven 依赖
<dependencies>
<!-- Apache POI 核心库 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version> <!-- 请使用最新稳定版 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version>
</dependency>
</dependencies>
Java 代码示例
import org.apache.poi.ss.usermodel.;
import org.apache.poi.ss.util.NumberToTextConverter;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class ExcelReader {
public static void main(String[] args) {
String filePath = "example.xlsx"; // 或 example.xls
try (FileInputStream fis = new FileInputStream(new File(filePath));
Workb
ook workbook = WorkbookFactory.create(fis)) {
// 获取第一个工作表
Sheet sheet = workbook.getSheetAt(0);
// 遍历每一行
for (Row row : sheet) {
// 遍历每一列
for (Cell cell : row) {
String cellValue = getCellStringValue(cell);
System.out.print(cellValue + "t");
}
System.out.println(); // 换行
}
} catch (IOException e) {
e.printStackTrace();
}
}
/
将 Cell 转换为 String,处理不同数据类型
/
private static String getCellStringValue(Cell cell) {
if (cell == null) {
return "";
}
CellType cellType = cell.getCellType();
if (cellType == CellType.STRING) {
return cell.getStringCellValue();
} else if (cellType == CellType.NUMERIC) {
// 判断是否为日期类型
if (DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue().toString();
} else {
// 避免科学计数法,转为整数或保留小数
double numericValue = cell.getNumericCellValue();
// 如果小数部分为0,则转为整数显示
if (numericValue == Math.floor(numericValue)) {
return String.valueOf((long) numericValue);
} else {
return String.valueOf(numericValue);
}
}
} else if (cellType == CellType.BOOLEAN) {
return String.valueOf(cell.getBooleanCellValue());
} else if (cellType == CellType.FORMULA) {
try {
// 尝试获取公式计算后的数值
return String.valueOf(cell.getNumericCellValue());
} catch (IllegalStateException e) {
// 如果公式返回字符串,则获取字符串值
return cell.getStringCellValue();
}
} else if (cellType == CellType.BLANK) {
return "";
} else {
return "";
}
}
}
🔍 关键说明
为什么用 WorkbookFactory.create()?
- 它会自动检测文件扩展名和内容,决定使用
HSSFWorkbook(.xls)还是XSSFWorkbook(.xlsx)。 - 你不需要手动判断文件类型,代码更简洁、健壮。
单元格类型处理
Excel 单元格可能有多种类型:
STRING:文本NUMERIC:数字(包括日期和整数)BOOLEAN:布尔值FORMULA:公式BLANK:空单元格
在 getCellStringValue() 方法中,我们对每种类型做了兼容处理,特别是:
- 日期判断:使用
DateUtil.isCellDateFormatted()判断数值型单元格是否为日期。 - 数字格式化:避免
0显示为0,而是显示为1。
性能考虑(大数据量)
Excel 文件非常大(如超过 10 万行),XSSF(.xlsx) 会占用大量内存,可能导致 OutOfMemoryError。
解决方案:使用 SXSSF(流式读取)
import org.apache.poi.xssf.streaming.SXSSFWorkbook; // 注意:SXSSFWorkbook 主要用于写入,读取大文件建议使用 Apache POI 的 Event Model (SAX) // 或者使用第三方库如 EasyExcel(推荐)
💡 强烈建议:对于生产环境的大文件读取,推荐使用 Alibaba EasyExcel,它基于 POI 封装,内存占用极低,API 更简洁。
🚀 替代方案:使用 EasyExcel(推荐用于生产环境)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import java.util.List;
public class EasyExcelReader {
public static void main(String[] args) {
String fileName = "example.xlsx";
// 读取数据
EasyExcel.read(fileName, DataModel.class, new ReadListener<DataModel>() {
@Override
public void invoke(DataModel data, AnalysisContext context) {
System.out.println(data.getName() + " - " + data.getAge());
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("所有数据读取完成!");
}
}).sheet().doRead();
}
}
// 数据模型
class DataModel {
private String name;
private Integer age;
// getter 和 setter
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; }
}
| 场景 | 推荐方案 |
|---|---|
| 小文件、简单需求、学习用途 | Apache POI(WorkbookFactory) |
| 大文件、高性能、生产环境 | Alibaba EasyExcel |
| 需要解析复杂公式或样式 | Apache POI |
如有具体需求(如只读某列、跳过表头、处理合并单元格等),可以进一步说明,我可以提供针对性代码。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/487321.html



