[alibaba/easyexcel]ExcelWriter.finish() 出错

2024-05-21 256 views
4

IO流来自于HttpServletResponse 版本:

  <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>easyexcel</artifactId>
         <version>2.2.6</version>
  </dependency>
   <dependency>
         <groupId>org.apache.poi</groupId>
         <artifactId>poi</artifactId>
         <version>3.17</version>
  </dependency>
2020-07-27 18:20:14 [Finalizer] WARN  com.alibaba.excel.ExcelWriter Destroy object failed
com.alibaba.excel.exception.ExcelGenerateException: Can not close IO.
    at com.alibaba.excel.context.WriteContextImpl.finish(WriteContextImpl.java:378) ~[easyexcel-2.2.6.jar!/:?]
    at com.alibaba.excel.write.ExcelBuilderImpl.finish(ExcelBuilderImpl.java:95) ~[easyexcel-2.2.6.jar!/:?]
    at com.alibaba.excel.ExcelWriter.finish(ExcelWriter.java:329) ~[easyexcel-2.2.6.jar!/:?]
    at com.alibaba.excel.ExcelWriter.finalize(ExcelWriter.java:340) [easyexcel-2.2.6.jar!/:?]
    at java.lang.System$2.invokeFinalize(System.java:1270) [?:1.8.0_191]
    at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:102) [?:1.8.0_191]
    at java.lang.ref.Finalizer.access$100(Finalizer.java:34) [?:1.8.0_191]
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:217) [?:1.8.0_191]
Caused by: java.lang.NullPointerException
    at org.apache.coyote.http11.Http11OutputBuffer.commit(Http11OutputBuffer.java:347) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.coyote.http11.Http11Processor.prepareResponse(Http11Processor.java:1399) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.coyote.AbstractProcessor.action(AbstractProcessor.java:346) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.coyote.Response.action(Response.java:175) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.coyote.Response.sendHeaders(Response.java:357) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:303) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.catalina.connector.OutputBuffer.close(OutputBuffer.java:263) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at org.apache.catalina.connector.CoyoteOutputStream.close(CoyoteOutputStream.java:157) ~[tomcat-embed-core-8.5.32.jar!/:8.5.32]
    at java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:241) ~[?:1.8.0_191]
    at java.util.zip.ZipOutputStream.close(ZipOutputStream.java:377) ~[?:1.8.0_191]
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.injectData(SXSSFWorkbook.java:394) ~[poi-ooxml-3.15.jar!/:3.15]
    at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:949) ~[poi-ooxml-3.15.jar!/:3.15]
    at com.alibaba.excel.context.WriteContextImpl.finish(WriteContextImpl.java:339) ~[easyexcel-2.2.6.jar!/:?]
    ... 7 more

回答

9

@icemanjc 你这个io流是来自HttpServletResponse?有具体的代码吗

7

@icemanjc 你这个io流是来自HttpServletResponse?有具体的代码吗 @Jiaxiayuan


@RequestMapping("/exportPerformDetail")
public void exportPerformDetail(@RequestBody PerformeStatisticReq req, HttpServletResponse response) throws IOException {
...

fileName = URLEncoder.encode(fileName, "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); ExcelWriterBuilder writerBuilder = EasyExcel.write(response.getOutputStream(), tClass); writerBuilder.autoCloseStream(Boolean.FALSE); ...

try{ ... writer = writerBuilder.build(); for (int i = 0; i < data.size(); i++) { // 写入数据 WriteSheet sheet = sheetBuilder.sheetName("sheet " + (i + 1)).registerConverter(new SimpleListStringConverter()).build(); writer.write(data.get(i), sheet); } } catch (Exception e) { log.error("导出失败", e); response.reset(); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); CommonResult result = CommonResult.createFailResult(e.getMessage()); try { response.getWriter().println(JSON.toJSONString(result)); } catch (IOException ex) { } }finally { // 关闭流 if (writer != null) { writer.finish(); } }

1

我也遇到这个问题了,一样的场景,有时候报错有时候不报错。

1

第一次下载导出会成功,紧接着后边的导出就会异常,需要过十几秒大概就又会下载成功。debug程序未执行完成前端就收到响应,有时是zip包,有时是空xls文件。尝试将WriteBuilder设置成自动关闭流,去掉异常处理并手动关闭流问题依旧

1

第一次下载导出会成功,紧接着后边的导出就会异常,需要过十几秒大概就又会下载成功。debug程序未执行完成前端就收到响应,有时是zip包,有时是空xls文件。尝试将WriteBuilder设置成自动关闭流,去掉异常处理并手动关闭流问题依旧

我后面解决这个问题了。我这边的情况是因为我在触发下载弹窗后1.5秒就把弹窗自动关闭了,造成服务端输出还没结束客户端就中断了连接。EasyExcel把异常信息封装得太严实,输出时只要抛了异常它就提示Can not close IO,我是debug到了具体的代码里才发现真正的原因的。

0

第一次下载导出会成功,紧接着后边的导出就会异常,需要过十几秒大概就又会下载成功。debug程序未执行完成前端就收到响应,有时是zip包,有时是空xls文件。尝试将WriteBuilder设置成自动关闭流,去掉异常处理并手动关闭流问题依旧

我后面解决这个问题了。我这边的情况是因为我在触发下载弹窗后1.5秒就把弹窗自动关闭了,造成服务端输出还没结束客户端就中断了连接。EasyExcel把异常信息封装得太严实,输出时只要抛了异常它就提示Can not close IO,我是debug到了具体的代码里才发现真正的原因的。

感谢,我也解决了问题,不过跟你情况不一样。 新建WriteSheet的时候以为可以不重复注册Converter,将builder缓存用于创建sheet页

ExcelWriterSheetBuilder builder = excelWriterBuilder.sheet();
WriteSheet sheet = sheetBuilder.sheetNo(sheetNo).sheetName(sheetName);

并且手动创建了ExcelWriter

ExcelWriter writer = excelWriterBuilder.build();

结果创建了两个ExcelWriter对象(sheet()方法也创建了一个),导致finish()方法被执行了两次,一次手动执行,一次ExcelWriter.finalize()执行,第一次流被关闭后,第二次就抛异常了.

7

第一次下载导出会成功,紧接着后边的导出就会异常,需要过十几秒大概就又会下载成功。debug程序未执行完成前端就收到响应,有时是zip包,有时是空xls文件。尝试将WriteBuilder设置成自动关闭流,去掉异常处理并手动关闭流问题依旧

我后面解决这个问题了。我这边的情况是因为我在触发下载弹窗后1.5秒就把弹窗自动关闭了,造成服务端输出还没结束客户端就中断了连接。EasyExcel把异常信息封装得太严实,输出时只要抛了异常它就提示Can not close IO,我是debug到了具体的代码里才发现真正的原因的。

感谢,我也解决了问题,不过跟你情况不一样。 新建WriteSheet的时候以为可以不重复注册Converter,将builder缓存用于创建sheet页

ExcelWriterSheetBuilder builder = excelWriterBuilder.sheet();
WriteSheet sheet = sheetBuilder.sheetNo(sheetNo).sheetName(sheetName);

并且手动创建了ExcelWriter

ExcelWriter writer = excelWriterBuilder.build();

结果创建了两个ExcelWriter对象(sheet()方法也创建了一个),导致finish()方法被执行了两次,一次手动执行,一次ExcelWriter.finalize()执行,第一次流被关闭后,第二次就抛异常了.

ExcelWriter.java 源代码finalize方法有问题,JVM gc时很有可能报错: com.alibaba.excel.ExcelWriter Destroy object failed ... ExcelGenerateException: Can not close IO.

/**
 * Close IO
 */
public void finish() {
    if (excelBuilder != null) {
        excelBuilder.finish(false);
    }
}

/**
 * Prevents calls to {@link #finish} from freeing the cache
 *
 */
@Override
protected void finalize() {
    try {
        finish();
    } catch (Throwable e) {
        LOGGER.warn("Destroy object failed", e);
    }
}
1

我这里也是偶现,有解决办法吗?