Java使用Apache POI和EasyExcel讀取Excel文件的實現(xiàn)方案
Java 讀取 Excel 文件核心依賴 Apache POI(兼容 .xls(Excel 97-2003)和 .xlsx(Excel 2007+))或 EasyExcel(阿里開源,低內存、高性能),以下是兩種主流方案的完整實現(xiàn),覆蓋「讀取簡單單元格、讀取指定sheet、讀取表頭+數(shù)據(jù)」等場景。
一、前置準備:引入依賴
方案 1:Apache POI(功能全,兼容所有Excel版本)
Maven 依賴(需同時引入 poi 和 poi-ooxml,分別對應 .xls 和 .xlsx):
<dependencies>
<!-- 核心依賴:處理 .xls -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.5</version> <!-- 推薦最新穩(wěn)定版 -->
</dependency>
<!-- 處理 .xlsx -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- 可選:簡化日期格式處理 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
</dependencies>
方案 2:EasyExcel(阿里開源,低內存,推薦大數(shù)據(jù)量)
Maven 依賴(僅需核心包,自動兼容 .xls/.xlsx):
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version> <!-- 最新版 -->
</dependency>
<!-- 可選:日志依賴(EasyExcel 依賴 slf4j) -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.9</version>
</dependency>
二、方案 1:Apache POI 讀取 Excel(通用場景)
場景 1:讀取所有sheet的所有單元格(基礎版)
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import java.io.FileInputStream;
import java.io.IOException;
public class POIExcelReader {
public static void main(String[] args) {
String filePath = "D:/test.xlsx"; // 替換為你的Excel文件路徑
// 區(qū)分 .xls 和 .xlsx
Workbook workbook = null;
try (FileInputStream fis = new FileInputStream(filePath)) {
if (filePath.endsWith(".xlsx")) {
workbook = new XSSFWorkbook(fis); // .xlsx
} else if (filePath.endsWith(".xls")) {
workbook = new HSSFWorkbook(fis); // .xls
} else {
throw new IllegalArgumentException("不支持的Excel格式");
}
// 遍歷所有sheet
for (Sheet sheet : workbook) {
System.out.println("===== Sheet名稱:" + sheet.getSheetName() + " =====");
// 遍歷所有行(跳過表頭:從第1行開始,rowNum=1)
for (Row row : sheet) {
// 遍歷該行所有單元格
for (Cell cell : row) {
// 獲取單元格值(統(tǒng)一格式)
String cellValue = getCellValue(cell);
System.out.print(cellValue + "\t");
}
System.out.println(); // 換行
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 工具方法:統(tǒng)一處理不同類型的單元格值
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING: // 字符串
return cell.getStringCellValue();
case NUMERIC: // 數(shù)字/日期
if (DateUtil.isCellDateFormatted(cell)) {
// 日期類型
return cell.getDateCellValue().toString();
} else {
// 數(shù)字類型(避免科學計數(shù)法)
return String.valueOf(cell.getNumericCellValue());
}
case BOOLEAN: // 布爾值
return String.valueOf(cell.getBooleanCellValue());
case FORMULA: // 公式
return cell.getCellFormula() + " = " + cell.getCachedFormulaResultType();
case BLANK: // 空單元格
return "";
default:
return "";
}
}
}
場景 2:讀取指定sheet和指定行(精準讀取)
// 讀取指定sheet(索引從0開始,或按名稱)
Sheet sheet = workbook.getSheetAt(0); // 第一個sheet
// 或 Sheet sheet = workbook.getSheet("用戶數(shù)據(jù)"); // 按名稱
// 讀取指定行(如第2行,rowNum=1)
Row targetRow = sheet.getRow(1);
if (targetRow != null) {
// 讀取指定單元格(如第3列,cellNum=2)
Cell targetCell = targetRow.getCell(2);
String value = getCellValue(targetCell);
System.out.println("指定單元格值:" + value);
}
// 遍歷有效行(跳過空行)
int lastRowNum = sheet.getLastRowNum(); // 最后一行索引
for (int rowNum = 1; rowNum <= lastRowNum; rowNum++) {
Row row = sheet.getRow(rowNum);
if (row == null) {
continue; // 跳過空行
}
// 讀取該行單元格
String name = getCellValue(row.getCell(0)); // 第1列:姓名
String age = getCellValue(row.getCell(1)); // 第2列:年齡
System.out.println("姓名:" + name + ",年齡:" + age);
}
三、方案 2:EasyExcel 讀取 Excel(高性能,推薦大數(shù)據(jù)量)
EasyExcel 無需加載整個Excel到內存,適合讀取十萬級以上數(shù)據(jù),核心是通過「監(jiān)聽器」逐行讀取。
步驟 1:定義數(shù)據(jù)實體(與Excel表頭映射)
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
// 對應Excel的表頭:姓名、年齡、手機號
@Data // Lombok注解,自動生成get/set
public class UserExcelDTO {
// value:Excel表頭名稱,index:列索引(可選)
@ExcelProperty(value = "姓名", index = 0)
private String name;
@ExcelProperty(value = "年齡", index = 1)
private Integer age;
@ExcelProperty(value = "手機號", index = 2)
private String phone;
}
步驟 2:自定義監(jiān)聽器(處理讀取到的數(shù)據(jù))
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
// 自定義監(jiān)聽器,逐行讀取數(shù)據(jù)并存儲
public class UserExcelListener extends AnalysisEventListener<UserExcelDTO> {
// 存儲讀取到的數(shù)據(jù)
private List<UserExcelDTO> dataList = new ArrayList<>();
// 每讀取一行數(shù)據(jù)觸發(fā)
@Override
public void invoke(UserExcelDTO user, AnalysisContext context) {
dataList.add(user);
System.out.println("讀取到數(shù)據(jù):" + user);
// 可在此處批量處理(如每1000條插入數(shù)據(jù)庫)
if (dataList.size() >= 1000) {
handleData(); // 處理數(shù)據(jù)
dataList.clear(); // 清空
}
}
// 所有數(shù)據(jù)讀取完成后觸發(fā)
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
handleData(); // 處理剩余數(shù)據(jù)
System.out.println("Excel讀取完成,總數(shù)據(jù)量:" + dataList.size());
}
// 數(shù)據(jù)處理邏輯(如插入數(shù)據(jù)庫)
private void handleData() {
if (!dataList.isEmpty()) {
// TODO: 批量插入數(shù)據(jù)庫/業(yè)務處理
System.out.println("批量處理" + dataList.size() + "條數(shù)據(jù)");
}
}
// 獲取讀取到的所有數(shù)據(jù)
public List<UserExcelDTO> getDataList() {
return dataList;
}
}
步驟 3:讀取Excel文件(核心代碼)
import com.alibaba.excel.EasyExcel;
import java.util.List;
public class EasyExcelReader {
public static void main(String[] args) {
String filePath = "D:/test.xlsx";
// 初始化監(jiān)聽器
UserExcelListener listener = new UserExcelListener();
// 讀取Excel(指定文件路徑、實體類、監(jiān)聽器)
EasyExcel.read(filePath, UserExcelDTO.class, listener)
.sheet("用戶數(shù)據(jù)") // 指定sheet名稱(可選,默認第一個)
.headRowNumber(1) // 表頭行數(shù)(默認1行)
.doRead(); // 執(zhí)行讀取
// 獲取所有數(shù)據(jù)
List<UserExcelDTO> dataList = listener.getDataList();
System.out.println("最終讀取到的數(shù)據(jù):" + dataList);
}
}
四、關鍵注意事項
1. 文件路徑與權限
- 確保文件路徑無中文/空格(避免
FileNotFoundException); - 若讀取服務器文件,需保證Java進程有文件讀取權限(如Linux下
chmod 755)。
2. 版本兼容
.xls(HSSFWorkbook)最大支持65536行,.xlsx(XSSFWorkbook)無行數(shù)限制;- EasyExcel 自動兼容兩種格式,無需手動區(qū)分。
3. 性能優(yōu)化
- Apache POI 讀取大數(shù)據(jù)量Excel易內存溢出,需用
SXSSFWorkbook(流式讀?。?; - EasyExcel 天生適合大數(shù)據(jù)量,無需額外配置。
4. 日期/數(shù)字格式
- Apache POI 需手動判斷日期格式(
DateUtil.isCellDateFormatted); - EasyExcel 可通過
@ExcelProperty(converter = DateConverter.class)自定義格式轉換。
五、兩種方案對比
| 方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| Apache POI | 功能全、兼容所有Excel特性 | 大數(shù)據(jù)量易內存溢出、代碼繁瑣 | 小數(shù)據(jù)量、需操作復雜Excel(公式/宏) |
| EasyExcel | 低內存、代碼簡潔、高性能 | 不支持宏/復雜公式 | 大數(shù)據(jù)量、普通數(shù)據(jù)讀取(推薦) |
六、常見問題解決
1.FileNotFoundException
- 檢查文件路徑是否正確(絕對路徑/相對路徑);
- 檢查文件是否被占用(如Excel未關閉)。
2. 內存溢出(OOM)
- Apache POI:改用
SXSSFWorkbook流式讀取; - 優(yōu)先使用 EasyExcel。
3. 日期讀取為數(shù)字
- Apache POI:通過
DateUtil.isCellDateFormatted判斷并轉換; - EasyExcel:配置日期轉換器。
核心原則:小數(shù)據(jù)量/復雜Excel用 Apache POI,大數(shù)據(jù)量/普通讀取用 EasyExcel;讀取時務必處理空單元格和格式轉換,避免空指針/格式錯誤。
以上就是Java使用Apache POI和EasyExcel讀取Excel文件的實現(xiàn)方案的詳細內容,更多關于Java Apache POI和EasyExcel讀取Excel的資料請關注腳本之家其它相關文章!
相關文章
Java創(chuàng)建類模式_動力節(jié)點Java學院整理
這篇文章主要為大家詳細介紹了Java創(chuàng)建類模式的相關方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
Idea安裝Eslint插件提示:Plugin NativeScript was not installed的問題
這篇文章主要介紹了Idea安裝Eslint插件提示:Plugin NativeScript was not installed的問題,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10
Spring-Bean創(chuàng)建對象的步驟方式詳解
在本篇文章里小編給大家分享的是關于Spring-Bean創(chuàng)建對象的步驟方式詳解內容,有興趣的朋友們跟著學習下。2020-02-02

