You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Apache POI导出Excel时出现“Stream closed”异常求助

问题分析与修复方案

嘿,我帮你看了下代码和抛出的异常,问题其实出在你用try-with-resources处理ServletOutputStream的方式上。

先看你遇到的异常:

Exceptin in excel Stream is closed [err] java.io.IOException: Stream is closed [err] at com.ibm.ws.http.channel.internal.outbound.HttpOutputStreamImpl.validate(HttpOutputStreamImpl.java:213) [err] at [internal classes]

你的核心代码片段如下:

public static void prepareDateForCSVGeneration(List<DataList> dataList,HttpServletResponse response) throws CashBookingInquiryServiceApplicationException { 
    try (ServletOutputStream out = response.getOutputStream()) { 
        XSSFWorkbook workbook = new XSSFWorkbook(); 
        //below method creates headers and rows 
        convertToExcel(workbook, dataList); 
        response.setContentType("text/vnd.ms-excel"); 
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx"); 
        workbook.write(out); 
        out.flush(); 
    } catch (IOException exception) { 
        System.out.println("Exceptin in excel "+exception.getMessage()); 
        exception.printStackTrace() ; 
    } 
}

问题根源

try-with-resources的特性是在代码块执行完毕后自动关闭所有实现了AutoCloseable接口的资源,这里的ServletOutputStream确实实现了该接口,所以try块结束后它会被自动关闭。但这个流是由Web容器(比如你用的IBM WebSphere)创建和管理的,容器在请求处理流程结束后,可能还会尝试对这个流做收尾操作,而你提前关闭了它,就触发了流已关闭的IO异常。

修复方案

我们需要调整资源管理的方式:

  1. 不要用try-with-resources管理ServletOutputStream,把它的生命周期交给容器控制,不要手动(包括自动)关闭。
  2. 手动管理你自己创建的XSSFWorkbook资源,确保它被正确关闭,避免内存泄漏。

修改后的代码如下:

public static void prepareDateForCSVGeneration(List<DataList> dataList, HttpServletResponse response) throws CashBookingInquiryServiceApplicationException { 
    ServletOutputStream out = null;
    XSSFWorkbook workbook = null;
    try { 
        out = response.getOutputStream();
        workbook = new XSSFWorkbook(); 
        convertToExcel(workbook, dataList); 
        // 修正xlsx对应的MIME类型,比text/vnd.ms-excel更规范
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); 
        response.setHeader("Content-Disposition", "attachment;filename=test.xlsx"); 
        workbook.write(out); 
        out.flush(); 
    } catch (IOException exception) { 
        System.out.println("Exception in excel " + exception.getMessage()); 
        exception.printStackTrace(); 
    } finally {
        // 关闭我们自己创建的workbook资源
        if (workbook != null) {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 不要关闭out,交给容器处理
    } 
}

额外小建议

  • 你原来的catch块里拼写了Exceptin,建议改成Exception,让日志更规范。
  • 原来设置的text/vnd.ms-excel是xls格式的MIME类型,xlsx格式用application/vnd.openxmlformats-officedocument.spreadsheetml.sheet更符合标准,虽然不影响下载,但推荐修正。

内容的提问来源于stack exchange,提问作者MiniSu

火山引擎 最新活动