【问题解决】apache.poi 3.1.4版本升级到 5.2.3,导出文件报错无法解析
3.1.4版本代码:
bash
/**
* 创建workbook
* @param inp
* @return
* @throws Exception
*/
public Workbook createworkbook(InputStream inp) throws Exception {
if (!inp.markSupported()) {
inp = new PushbackInputStream(inp, 8);
}
if (POIFSFileSystem.hasPOIFSHeader(inp)) {
return new HSSFWorkbook(inp);
}
if (POIXMLDocument.hasOOXMLHeader(inp)) {
return new XSSFWorkbook(OPCPackage.open(inp));
}
throw new IllegalArgumentException("你的excel版本目前poi解析不了");
}
在POI 4.0.x版本过后,POIFSFileSystem.hasPOIFSHeader()与 POIXMLDocument.hasOOXMLHeader()便弃用了,所以我们需要找到新版本的替代方法,为此查阅了不少资料。
这里有两个方案可以参考一下:
java
public Workbook createworkbook(InputStream inp) throws Exception {
try (PushbackInputStream pushbackInputStream = new PushbackInputStream(inp, 8)) {
byte[] header = new byte[8];
int read = pushbackInputStream.read(header);
pushbackInputStream.unread(header, 0, read);
if (POIUtils.hasOOXMLHeader(header)) {
return new XSSFWorkbook(OPCPackage.open(pushbackInputStream));
} else if (POIUtils.hasPOIFSHeader(header)) {
return new HSSFWorkbook(pushbackInputStream);
} else {
throw new IllegalArgumentException("不支持的 Excel 格式");
}
}
}
主要变更如下:
- 使用
POIUtils.hasOOXMLHeader(header)
方法替换POIDataSamples.getSpreadSheetInstance().acceptsFile(header)
方法。这个方法可以检测 XSSF 格式(OOXML)。 - 使用
POIUtils.hasPOIFSHeader(header)
方法检测 HSSF 格式(97-2003 Excel)。 - 如果以上两种方式都无法识别,则抛出一个自定义的异常。
这种方式可以有效地替换之前的代码,并适用于 Apache POI 5.2.3 版本。
需要注意的是,需要引入 org.apache.poi.util.POIUtils
类,这个类是 Apache POI 5.2.3 中新增的一个工具类,提供了一些常用的工具方法。
2.
java
public Workbook createworkbook(InputStream inp) throws Exception {
try (PushbackInputStream pushbackInputStream = new PushbackInputStream(inp, 8)) {
byte[] header = new byte[8];
int read = pushbackInputStream.read(header);
pushbackInputStream.unread(header, 0, read);
if (isXSSF(header)) {
return new XSSFWorkbook(OPCPackage.open(pushbackInputStream));
} else if (isHSSF(header)) {
return new HSSFWorkbook(pushbackInputStream);
} else {
throw new IllegalArgumentException("不支持的 Excel 格式");
}
}
}
private boolean isXSSF(byte[] header) {
// 检查 OOXML 文件头标识
return header[0] == (byte) 0x50 && header[1] == (byte) 0x4B && header[2] == (byte) 0x03 && header[3] == (byte) 0x04;
}
private boolean isHSSF(byte[] header) {
// 检查 POIFS 文件头标识
return header[0] == (byte) 0xD0 && header[1] == (byte) 0xCF && header[2] == (byte) 0x11 && header[3] == (byte) 0xE0;
}
这个替代方案中,自己实现了 isXSSF
和 isHSSF
方法来检测 OOXML 和 POIFS 文件头标识,达到了同样的效果。
踩坑啊!