首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Apache POI 讀取 Excel 完整指南:兼容 .xls/.xlsx、WorkbookFactory 統一入口

     編輯:Java 相關知識

POI 核心組件

組件支持格式說明
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>

統一入口:WorkbookFactory(推薦)

自動識別文件格式(通過文件頭魔數),返回 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 事件,極低內存解析百萬行。

寫入 Excel 速覽

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 的標準庫。核心口訣:

  1. 讀取統一用 WorkbookFactory.create(),自動兼容 .xls/.xlsx
  2. 單元格值獲取用 DataFormatter,避免類型轉換陷阱
  3. 大文件用 SAX 流式讀取,避免全量載入 OOM
  4. 寫入大數據用 SXSSFWorkbook,滑動窗口控制內存

掌握這四點,覆蓋 95% 以上 Excel 業務場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved