最近使用Apache poi 做excel导出的功能,遇到了如下问题:
Your stream was neither an OLE2 stream, nor an OOXML stream
起初对比其他的web工程,没有发现如何解决。最后找到抛出此异常的源码:
org.apache.poi.ss.usermodel.WorkbookFactory.create(WorkbookFactory.java:75)
public static Workbook create(InputStream inp) throws IOException, InvalidFormatException {
if (!((InputStream)inp).markSupported()) {
inp = new PushbackInputStream((InputStream)inp, 8);
}
if (POIFSFileSystem.hasPOIFSHeader((InputStream)inp)) {
return new HSSFWorkbook((InputStream)inp);
} else if (POIXMLDocument.hasOOXMLHeader((InputStream)inp)) {
return new XSSFWorkbook(OPCPackage.open((InputStream)inp));
} else {
throw new IllegalArgumentException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
}
可以看到,在调用WorkbookFactory.create(inputStream)
来创建Workbook时,会根据文件类型(文件头)来区别、创建合适的Workbook对象。如果不满足前两个if条件里的hasPOIFSHeader()
方法,就会抛出异常。而两个if里的hasPOIFSHeader()方法就是针对Excel2003和Excel2007的判断,读取文件流中的文件头(byte[8])信息去判断。
那既然是根据文件的头部信息去比对进行判断的,并且excel只有2003和2007两个版本,那为什么放在classpath下的excel模板读取后创建WorkBook时,文件header判断都不符合呢?
最后找到原因:maven编译打包时,将resources下的资源文件转码了。最终web工程打出的jar/war包,里面归档进去的excel模板文件都是乱码,文件头信息被修改,导致poi根本无法识别这样的excel文件。
解决办法:
项目的pom.xml中添加maven资源插件
<plugins>
<!-- 让maven不编译xls文件,但仍将其打包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
总结
1、推荐使用poi-ooxml中的WorkbookFactory.create(inputStream)
来创建Workbook,因为HSSFWorkbook和XSSFWorkbook都实现了Workbook接口。(Excel2003和Excel2007两个版本在此通过文件header进行适配)
2、当你的工程中,需要放入一些静态资源文件作为模板,比如excel填充模板,word模板(里面有些固定样式,程序运行时用模板导出报表类的),这个时候,最好都配置maven去除资源文件不被转码。下面的链接有2种方式。
Maven 打包 过滤资源文件
https://blog.csdn.net/qing_mei_xiu/article/details/80661216