POI读取excel报错

POI读取excel报错解决方案:兼容 xls 与 xlsx 格式

在使用 POI 读取 Excel 文件时,因文件格式(.xls.xlsx)不同常出现格式不匹配的错误。本文将详细解析错误原因,提供通用解决方案,并介绍 WorkbookFactory 的使用技巧,帮助你无缝兼容两种格式。

错误原因分析

错误信息解读

当使用 POIFSFileSystem 读取 .xlsx 文件时,会出现以下错误:

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)
  • 原因:
    • .xls(Excel 2003 及以前)基于 OLE2 格式,需用 HSSF 相关类(如 POIFSFileSystemHSSFWorkbook)处理;
    • .xlsx(Excel 2007 及以后)基于 XML 格式,需用 XSSF 相关类(如 XSSFWorkbook)处理。
    • 若用 HSSF 类读取 .xlsx 文件(或反之),会因格式不匹配报错。

常见错误用法

手动判断文件格式并选择对应类,容易因判断逻辑错误导致兼容问题:

// 错误示例:仅支持 .xls 格式,无法处理 .xlsx  
if (file.getName().endsWith(".xls")) {  
    workbook = new HSSFWorkbook(new FileInputStream(file));  
} else {  
    throw new RuntimeException("不支持的文件格式");  
}

通用解决方案:使用 WorkbookFactory

POI 提供 WorkbookFactory 工具类,可自动识别文件格式并创建对应的 Workbook 实例(HSSFWorkbookXSSFWorkbook),无需手动判断格式。

核心代码实现

import org.apache.poi.ss.usermodel.Workbook;  
import org.apache.poi.ss.usermodel.WorkbookFactory;  
import java.io.File;  
import java.io.FileInputStream;  
import java.io.IOException;  

public class ExcelReader {  

    /**  
     * 读取 Excel 文件(兼容 .xls 和 .xlsx)  
     * @param file 上传的 Excel 文件  
     * @return Workbook 实例(HSSFWorkbook 或 XSSFWorkbook)  
     */  
    public static Workbook readExcel(File file) {  
        try (FileInputStream fis = new FileInputStream(file)) {  
            // 自动识别格式并创建 Workbook  
            return WorkbookFactory.create(fis);  
        } catch (IOException e) {  
            throw new RuntimeException("读取 Excel 失败:" + e.getMessage(), e);  
        }  
    }  

    // 使用示例  
    public static void main(String[] args) {  
        File excelFile = new File("data.xlsx"); // 可替换为 .xls 文件  
        try (Workbook workbook = readExcel(excelFile)) {  
            // 读取工作表、行、单元格(后续操作与格式无关)  
            System.out.println("工作表数量:" + workbook.getNumberOfSheets());  
            // ... 处理逻辑 ...  
        }  
    }  
}

WorkbookFactory 的优势

  • 自动兼容:无需判断 .xls.xlsx,内部根据文件头信息自动选择 HSSFXSSF
  • 资源安全:推荐配合 try-with-resources 语法使用,自动关闭流和 Workbook,避免资源泄露;
  • 支持加密文件:可通过重载方法 WorkbookFactory.create(fis, password) 读取加密的 Excel 文件(需传入密码)。

扩展:文件格式手动判断(可选)

若需手动区分格式(如特殊业务逻辑),可通过文件头或后缀判断:

通过文件头判断(更可靠)

.xls.xlsx 的文件头标识不同,可读取文件前几个字节判断:

/**  
 * 判断文件是否为 .xlsx 格式(基于文件头)  
 */  
public static boolean isXlsx(File file) {  
    try (FileInputStream fis = new FileInputStream(file)) {  
        byte[] header = new byte[4];  
        fis.read(header);  
        // .xlsx 文件头为 [80, 75, 3, 4](对应 ZIP 格式,因 .xlsx 本质是 ZIP 压缩包)  
        return header[0] == 80 && header[1] == 75 && header[2] == 3 && header[3] == 4;  
    } catch (IOException e) {  
        return false;  
    }  
}  

// 使用  
if (isXlsx(file)) {  
    workbook = new XSSFWorkbook(new FileInputStream(file));  
} else {  
    workbook = new HSSFWorkbook(new FileInputStream(file));  
}

通过文件后缀判断(简单但不绝对)

public static boolean isXlsxBySuffix(String fileName) {  
    return fileName.toLowerCase().endsWith(".xlsx");  
}
  • 注意:后缀可被手动修改(如 .xls 文件改名为 .xlsx),可能导致误判,推荐优先使用文件头判断。

常见问题与解决方案

1. WorkbookFactory 读取时报错 “Invalid header signature”

  • 原因:文件不是有效的 Excel 格式(如伪装成 .xls 的文本文件);
  • 解决:先校验文件格式(如通过文件头),再调用 WorkbookFactory.create()

2. 大文件读取内存溢出

  • 原因XSSFWorkbook 会将整个 Excel 加载到内存,超大文件(如 10 万行数据)可能导致 OOM;

  • 解决:使用 POI 的事件驱动模式(SXSSFWorkbook或XSSFReader)处理大文件:

// 处理超大 .xlsx 文件(仅加载部分行到内存)  
SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(fis), 100); // 仅保留 100 行在内存  

3. 依赖冲突导致类找不到

  • 原因:项目中存在多个版本的 POI 依赖,或缺失 poi-ooxml 依赖;

  • 解决

    • 确保 poipoi-ooxml 版本一致(如均为 4.1.2);

    • 排除冲突依赖:

<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi-ooxml</artifactId>  
    <version>4.1.2</version>  
    <exclusions>  
        <exclusion>  
            <groupId>org.apache.poi</groupId>  
            <artifactId>poi</artifactId>  
        </exclusion>  
    </exclusions>  
</dependency>