[alibaba/easyexcel]Stream Closed 异常

2024-05-23 193 views
8

触发场景描述 写入本地excel文件报错

触发Bug的代码 源码不方便贴,贴了简要过程代码,版本2.1.6 com.alibaba.excel.EasyExcelFactory#write(java.lang.String, java.lang.Class) 创建ExcelWriter对象 com.alibaba.excel.EasyExcelFactory#writerSheet(java.lang.String) 创建WriteSheet对象 com.alibaba.excel.ExcelWriter#write(java.util.List, com.alibaba.excel.write.metadata.WriteSheet) 写入数据

提示的异常或者没有达到的效果 写入数据报错了,本地文件为空,异常信息如下 Destroy object failed com.alibaba.excel.exception.ExcelGenerateException: Can not close IO. at com.alibaba.excel.context.WriteContextImpl.finish(WriteContextImpl.java:358) at com.alibaba.excel.write.ExcelBuilderImpl.finish(ExcelBuilderImpl.java:101) at com.alibaba.excel.ExcelWriter.finish(ExcelWriter.java:328) at com.alibaba.excel.ExcelWriter.finalize(ExcelWriter.java:338) at java.lang.System$2.invokeFinalize(System.java:1270) at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:98) at java.lang.ref.Finalizer.access$100(Finalizer.java:34) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:210) Caused by: java.io.IOException: Stream Closed at java.io.FileOutputStream.writeBytes(Native Method) at java.io.FileOutputStream.write(FileOutputStream.java:326) at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:282) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.BufferedWriter.write(BufferedWriter.java:230) at java.io.Writer.write(Writer.java:157) at org.apache.poi.xssf.streaming.SheetDataWriter.writeCell(SheetDataWriter.java:238) at org.apache.poi.xssf.streaming.SheetDataWriter.writeRow(SheetDataWriter.java:159) at org.apache.poi.xssf.streaming.SXSSFSheet.flushOneRow(SXSSFSheet.java:1893) at org.apache.poi.xssf.streaming.SXSSFSheet.flushRows(SXSSFSheet.java:1871) at org.apache.poi.xssf.streaming.SXSSFSheet.flushRows(SXSSFSheet.java:1882) at org.apache.poi.xssf.streaming.SXSSFWorkbook.write(SXSSFWorkbook.java:931) at com.alibaba.excel.context.WriteContextImpl.finish(WriteContextImpl.java:314)

回答

7

补充说明下: 1、不是一定出现,五一期间生产出现过几次,但是找不到还原的方式 2、数据导出通过一个异步线程池处理的,线程池提交任务后,执行了shutdown方法

4

初步排查推测: ExcelWriter重写了finalize方法 我们在写入数据时调用了ExcelWriter的finish方法 com.alibaba.excel.context.WriteContextImpl#finish 方法的finished变量不是线程安全的,是否是这个原因 盼复!

6

com.alibaba.excel.exception.ExcelGenerateException: Can not close IO. at com.alibaba.excel.context.WriteContextImpl.finish(WriteContextImpl.java:378) at com.alibaba.excel.write.ExcelBuilderImpl.finish(ExcelBuilderImpl.java:95) at com.alibaba.excel.ExcelWriter.finish(ExcelWriter.java:329) at com.alibaba.excel.ExcelWriter.finalize(ExcelWriter.java:340)

the same problem , version 2.2.5

5

@jungecodeman 我看你关了issue。解决了吗。 我这里也有个问题,大量表格写入的时候,会被调用finalize(话说为什么easyexcel要重写这个方法?这不是gc调用的吗)。 然后导致提前调用finish方法。后台好像要设置一个参数为false才能解决该问题。 @zhuangjiaju

4

@jungecodeman 我看你关了issue。解决了吗。 我这里也有个问题,大量表格写入的时候,会被调用finalize(话说为什么easyexcel要重写这个方法?这不是gc调用的吗)。 然后导致提前调用finish方法。后台好像要设置一个参数为false才能解决该问题。 @zhuangjiaju

框架本身是没有问题的,我们之前业务代码有问题,原因是这样的: 我们导出时,会先计算下导出的数据总数,然后切分到不同的excel,比如一个excel20w行数据,假设数据一开始count出来是35w行,那么会写2个excel,写第二个excel的时候我们的判断数据已经读取完成的条件不对(数据在不断的变化),导致压根没有执行finish(),具体源码不方便展示,我遇到的核心问题就是我们先算了总数,然后数据在变,导致finish方法未执行

2

@jungecodeman finish方法不是放在finally中的吗?看来我们情况不一样

6

@jungecodeman finish方法不是放在finally中的吗?看来我们情况不一样

应该是一样的,finish手工掉诶,我细化下过程:1、计算总行数 2、数据库我们是一行一行返回,累积满1000行掉一次write方法 3、满一个excel的总限制大小,掉一次finish 4、没有数据了(最后一个文件)掉一次finish 我们出问题是在最后excel的finish判断条件不对,导致没有执行finish 5、执行压缩打包上传到OSS,上传完成删除文件 为啥会出Can not close IO呢?因为最后一个的finish压根没执行,然后执行第5步的时候,文件都给删掉了,对象销毁的时候,会触发finish方法执行,就报错了