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

POI 解析 Excel 2003/2007 統一入口:WorkbookFactory 解決 "OLE2 vs OOXML" 兼容難題

     編輯:Java 綜合教學

錯誤現場

上傳 .xlsx 文件解析時拋出:


org.apache.poi.poifs.filesystem.OfficeXmlFileException:
The supplied data appears to be in the Office 2007+ XML.
You are calling the part of POI that deals with OLE2 Office Documents.
You need to call a different part of POI to process this data (eg XSSF instead of HSSF)

根因:代碼硬編碼使用 HSSFWorkbook(僅支持 .xls OLE2 格式),但文件實為 .xlsx (OOXML 格式),需用 XSSFWorkbook。

一鍵解決:WorkbookFactory 自適應識別


// 核心一行代碼:自動識別 .xls / .xlsx / .xlsm 等格式
Workbook wb = WorkbookFactory.create(inputStream);

WorkbookFactory.create() 內部通過文件頭魔數(Magic Number)判斷格式,返回統一 Workbook 介面,屏蔽 HSSF/XSSF 差異。

Maven 依賴配置 (版本統一原則)


<properties>
    <poi.version>5.3.0</poi.version> <!-- 統一版本,避免傳遞依賴衝突 -->
</properties>

<dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>${poi.version}</version>
    </dependency>
    <!-- poi-ooxml-schemas 5.0.0+ 已合併入 poi-ooxml,無需單獨引入 -->
</dependencies>

版本建議:使用 5.x 系列(如 5.3.0),修復大量安全漏洞、性能優化、支持最新 Excel 特性。舊版 3.14-beta1 已停止維護。

Spring MVC 完整解析服務示例


@Service
public class ExcelParseService {

    public List parse(MultipartFile file) throws IOException {
        // 1. 基礎校驗
        String filename = file.getOriginalFilename();
        if (filename == null || !(filename.endsWith(".xls") || filename.endsWith(".xlsx"))) {
            throw new IllegalArgumentException("僅支持 .xls/.xlsx 格式");
        }

        // 2. 統一入口解析
        try (InputStream is = file.getInputStream();
             Workbook wb = WorkbookFactory.create(is)) {

            Sheet sheet = wb.getSheetAt(0); // 默認首張表
            return parseSheet(sheet);
        }
    }

    private List parseSheet(Sheet sheet) {
        List list = new ArrayList<>();
        for (Row row : sheet) {
            if (row.getRowNum() == 0) continue; // 跳過表頭
            Customer c = new Customer();
            c.setName(getCellString(row.getCell(0)));
            c.setPhone(getCellString(row.getCell(1)));
            c.setEmail(getCellString(row.getCell(2)));
            list.add(c);
        }
        return list;
    }

    private String getCellString(Cell cell) {
        if (cell == null) return "";
        return switch (cell.getCellType()) {
            case STRING -> cell.getStringCellValue();
            case NUMERIC -> DateUtil.isCellDateFormatted(cell) 
                ? cell.getLocalDateTimeCellValue().toString() 
                : String.valueOf((long) cell.getNumericCellValue());
            case BOOLEAN -> String.valueOf(cell.getBooleanCellValue());
            case FORMULA -> cell.getCellFormula();
            default -> "";
        };
    }
}

常見坑位避雷指南

坑點現象解決
大文件 OOMWorkbookFactory 全量載入內存用 SXSSFWorkbook (流式寫入) 或 XSSFReader (SAX 事件流式讀取)
數字儲存格讀成科學計數法getNumericCellValue() 返回 double用 DataFormatter 格式化輸出,或判斷類型轉 long
日期類型誤判NUMERIC 儲存格實為日期必須調用 DateUtil.isCellDateFormatted(cell) 判斷
公式單元格報錯未計算公式值調用 FormulaEvaluator.evaluateAll(wb) 預計算
.xls 文件實為 HTML/CSVWorkbookFactory 拋異常前置校驗文件頭魔數,或捕獲異常降級嘗試其他解析器

總結

WorkbookFactory.create() 是 POI 解析 Excel 的黃金單一入口,屏蔽了 OLE2 (.xls) 與 OOXML (.xlsx) 的底層差異。配合統一版本依賴、流式讀取大文件策略、DataFormatter 統一單元格輸出,構建健壯的 Excel 導入服務。

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