| 組件 | 支持格式 | 說明 |
|---|---|---|
| HSSF | .xls (Excel 97-2003) | OLE2 復合文檔格式 |
| XSSF | .xlsx (Excel 2007+) | OOXML 標準 (ZIP + XML) |
| SXSSF | .xlsx (大數據流式寫入) | 低內存佔用,僅支持寫入 |
<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>
自動識別文件格式(通過文件頭魔數),返回 Workbook 介面,屏蔽 HSSF/XSSF 差異。
public Workbook readWorkbook(File file) throws IOException, InvalidFormatException {
try (InputStream is = new FileInputStream(file)) {
// 必須支持 mark/reset,或包裝為 PushbackInputStream
return WorkbookFactory.create(is);
}
}
原理:POIFSFileSystem.hasPOIFSHeader() 檢測 OLE2 頭;POIXMLDocument.hasOOXMLHeader() 檢測 OOXML 頭。即使修改副檔名也能正確識別。
public void readExcel(File file) {
try (Workbook wb = WorkbookFactory.create(file)) {
for (Sheet sheet : wb) { // 遍歷所有 Sheet
System.out.println("=== Sheet: " + sheet.getSheetName() + " ===");
for (Row row : sheet) { // 遍歷所有行
StringBuilder sb = new StringBuilder();
for (Cell cell : row) { // 遍歷所有單元格
sb.append(getCellValue(cell)).append("\t");
}
System.out.println(sb);
}
}
} catch (Exception e) {
throw new RuntimeException("讀取失敗", e);
}
}
private String getCellValue(Cell cell) {
if (cell == null) return "";
switch (cell.getCellType()) {
case STRING: return cell.getStringCellValue();
case NUMERIC:
if (DateUtil.isCellDateFormatted(cell))
return cell.getDateCellValue().toString();
return String.valueOf(cell.getNumericCellValue());
case BOOLEAN: return String.valueOf(cell.getBooleanCellValue());
case FORMULA: return cell.getCellFormula(); // 或評估後的值
case BLANK: return "";
case ERROR: return "#ERROR";
default: return "";
}
}
| 問題 | 解決方案 |
|---|---|
| 數字儲存為科學計數法/長整數 | 用 DataFormatter 獲取顯示文本:new DataFormatter().formatCellValue(cell) |
| 日期類型判斷 | DateUtil.isCellDateFormatted(cell),再 getDateCellValue() |
| 公式單元格 | cell.getCellType() == FORMULA,需 FormulaEvaluator.evaluate(cell) 獲取計算值 |
| 合併單元格 | sheet.getMergedRegions() 獲取區域,邏輯處理顯示值 |
| 大文件 OOM | 用 SXSSFWorkbook (僅寫) 或 XSSFReader (SAX 事件流讀取) |
| 密碼保護文件 | WorkbookFactory.create(is, password) 或 Biff8EncryptionKey |
try (OPCPackage pkg = OPCPackage.open(file)) {
XSSFReader reader = new XSSFReader(pkg);
SharedStringsTable sst = reader.getSharedStringsTable();
XMLReader parser = XMLReaderFactory.createXMLReader();
parser.setContentHandler(new MySheetHandler(sst));
try (InputStream sheetIs = reader.getSheet("rId1")) {
parser.parse(new InputSource(sheetIs));
}
}
實現 MySheetHandler extends DefaultHandler 處理 startElement/endElement/characters 事件,極低內存解析百萬行。
try (Workbook wb = new XSSFWorkbook(); // 或 SXSSFWorkbook(100) 窗口 100 行
FileOutputStream fos = new FileOutputStream("out.xlsx")) {
Sheet sheet = wb.createSheet("Data");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("ID");
header.createCell(1).setCellValue("Name");
for (int i = 1; i <= 100; i++) {
Row row = sheet.createRow(i);
row.createCell(0).setCellValue(i);
row.createCell(1).setCellValue("User" + i);
}
wb.write(fos);
}
Apache POI 是 Java 操作 Excel 的標準庫。核心口訣:
掌握這四點,覆蓋 95% 以上 Excel 業務場景。