将Apache Poi Workbook注册为Spring IOC Bean时遇空文件异常的解决咨询
解决Spring IOC中Apache Poi Workbook Bean抛出EmptyFileException的问题
在将Apache Poi Workbook注册为Spring IOC管理的Bean时,抛出异常:
Caused by: org.apache.poi.EmptyFileException: The supplied file was empty (zero bytes long)
实际文件非空,且在非Spring管理的独立测试类中可正常创建Workbook实例。相关代码如下:
@Bean public FileInputStream getInputStream() { try { return new FileInputStream(EXCEL_FILE_PATH); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } @Bean public Workbook workbook() { try { Workbook workbook = WorkbookFactory.create(getInputStream()); getInputStream().close(); return workbook; } catch (IOException e) { e.printStackTrace(); } return null; }
上述代码位于标注了@Configuration的配置类中。
问题原因分析
- 单例流的复用问题:
getInputStream()被标记为@Bean,Spring会将其作为单例Bean缓存。流是有状态的资源,一旦被WorkbookFactory.create()读取完毕,指针会移动到文件末尾,后续复用该流时会读取到0字节。此外,代码中两次调用getInputStream(),第二次拿到的是同一个已被读取过的流,进一步加剧了问题。 - 路径问题导致流为null:若Spring环境中
EXCEL_FILE_PATH对应的文件路径不正确(比如相对路径的基准目录与独立测试不同),会触发FileNotFoundException,此时getInputStream()返回null,而WorkbookFactory.create(null)会抛出EmptyFileException。 - 流关闭方式不当:手动关闭流容易出现重复关闭或未正确关闭的情况,且未处理流读取失败的异常传播。
解决方案
方案一:移除流的Bean注册,使用私有方法创建一次性流
将getInputStream()改为私有方法,避免Spring将其作为单例Bean管理,每次调用都创建新的流,并使用try-with-resources自动关闭流:
@Configuration public class ExcelConfig { private static final String EXCEL_FILE_PATH = "你的文件绝对路径或正确的相对路径"; private FileInputStream getInputStream() throws FileNotFoundException { return new FileInputStream(EXCEL_FILE_PATH); } @Bean public Workbook workbook() { try (FileInputStream inputStream = getInputStream()) { return WorkbookFactory.create(inputStream); } catch (IOException e) { throw new RuntimeException("创建Workbook失败", e); } } }
方案二:直接在WorkBean方法中创建流(简化版)
省去单独的流方法,直接在workbook()中创建并使用流:
@Configuration public class ExcelConfig { private static final String EXCEL_FILE_PATH = "你的文件路径"; @Bean public Workbook workbook() { try (FileInputStream inputStream = new FileInputStream(EXCEL_FILE_PATH)) { return WorkbookFactory.create(inputStream); } catch (FileNotFoundException e) { throw new RuntimeException("未找到Excel文件:" + EXCEL_FILE_PATH, e); } catch (IOException e) { throw new RuntimeException("读取Excel文件失败", e); } } }
方案三:使用Spring ResourceLoader解决路径问题
如果是路径问题导致的文件找不到,推荐使用Spring的ResourceLoader来安全加载文件,避免相对路径的歧义:
@Configuration public class ExcelConfig { @Bean public Workbook workbook(ResourceLoader resourceLoader) { // 从类路径加载文件,适用于放在resources目录下的文件 Resource resource = resourceLoader.getResource("classpath:excel/example.xlsx"); try (InputStream inputStream = resource.getInputStream()) { return WorkbookFactory.create(inputStream); } catch (IOException e) { throw new RuntimeException("加载类路径下的Excel文件失败", e); } } }
内容的提问来源于stack exchange,提问作者SimeonKV
相关产品推荐
相关产品推荐

