apache poi库解析报错;java.io.IOException: Your InputStream was neither an OLE2 stream, nor an OOXML str
最近业务需要解析excel,使用apache poi库
在vscode中一切顺利。打包为jar丢到生产环境时报错:
1 | java.io.IOException: Your InputStream was neither an OLE2 stream, nor an OOXML stream or you haven't provide the poi-ooxml*.jar in the classpath/modulepath - FileMagic: OOXML, having providers: [org.apache.poi.hssf.usermodel.HSSFWorkbookFactory@405294c8] |
搜了一圈答案都和实际不符,最后在 https://stackoverflow.com/questions/67884617/apache-poi-excel-writer-works-in-ide-but-not-in-fat-jar-java-io-ioexception-yo 这个帖子下找到了答案
问题的根本是:
Apache POI使用META-INF/services目录下的文件来识别可用的服务提供者。
当使用Maven的maven-assembly-plugin打包成fat JAR时,来自poi和poi-ooxml的重名服务提供者文件没有被正确合并,导致在运行时只有一个提供者可用,无法正确处理Excel文件。
什么是服务提供者呢?这是一种服务发现机制,即 Java SPI (Service Provider Interface) ,允许应用程序动态发现和加载服务实现。它基于以下约定:
服务提供者在 META-INF/services/ 目录下创建以服务接口全限定名命名的文件
文件内容是实现该接口的类的全限定名列表
ServiceLoader 类用于加载这些服务实现
例如,如果有一个接口 com.example.MyService,其实现类是 com.example.impl.MyServiceImpl,则会有一个文件:
META-INF/services/com.example.MyService 内容为 com.example.impl.MyServiceImpl
当使用 Maven 打包成 Fat JAR(包含所有依赖的单一 JAR 文件)时,会出现一个问题:
如果多个 JAR 包中都有同名的服务提供者配置文件(如 META-INF/services/com.example.MyService),在合并时这些文件会相互覆盖,导致只有一个文件被保留,其他的实现类信息丢失。
这正是 Apache POI 在打包成 JAR 后出现问题的原因。poi 和 poi-ooxml 模块都有自己的服务提供者配置文件,但在打包时这些文件没有被正确合并。
知道问题之后解决起来就很简单了,我的方案是 将maven-assembly-plugin替换为maven-shade-plugin,并添加ServicesResourceTransformer合并服务提供者文件
修改前:
1 | <plugin> |
修改后:
1 | <plugin> |
关键的变化是添加了ServicesResourceTransformer,它能够正确合并来自不同JAR包中重名的服务提供者文件,而不是仅保留一个
问题解决
本文标题:apache poi库解析报错;java.io.IOException: Your InputStream was neither an OLE2 stream, nor an OOXML str
文章作者:meteor
发布时间:2025-06-20
最后更新:2025-06-20
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!
分享