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相关类(如POIFSFileSystem、HSSFWorkbook)处理;.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 实例(HSSFWorkbook 或 XSSFWorkbook),无需手动判断格式。
核心代码实现
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,内部根据文件头信息自动选择HSSF或XSSF; - 资源安全:推荐配合 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依赖;解决:
确保
poi和poi-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>