偶尔发生File has been moved - cannot be read again,其实是个误解

使用poi上传.xlsx文件时,出现如下错误

Exception in thread "pool-3-thread-2" java.lang.IllegalStateException: File has been moved - cannot be read again
    at org.springframework.web.multipart.commons.CommonsMultipartFile.getInputStream(CommonsMultipartFile.java:125)
    at cn.dataenergy.stat.yxjlbj.web.JlpbbjController$1.run(JlpbbjController.java:200)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)

注意该问题是偶尔发生,并非每次都能重现。而且发生的概率很低,但是一发生,可能连续多次导入都会爆同样的错。

第一感这应该是一个多线程问题,因为不是每次能重现很有可能是资源竞争。同时代码中也确实用了多线程.在我的controller中:

threadool.execute(new Runnable() {
              @Override
              public void run() {
                 try {
                            File tmpFile = new File(filepath);
                            InputStream inputStream = file.getInputStream();// 直接将文件读入到刘中
                            FileUtils.copyInputStreamToFile(inputStream, tmpFile);
                            Workbook wb = createworkbook(new FileInputStream(tmpFile));
                            tmpFile.delete();// 删除本地文件
                            String[] strExcelFlag = jlpbbjService.getExcelFlag(wb);
                            jlpbbjService.yxjlImportAndCompare(wb,
                            Integer.valueOf(strExcelFlag[1]), type,meterCompareTask);       
                            inputStream.close();
                 } catch (IOException e) {
                    e.printStackTrace();
                 }
             }
         });

 

出错的地方正是

 file.getInputStream();// 直接将文件读入到刘中

这里。这里只帖上了关键的代码。上传文件的处理可能是很耗时的,所以新建了一个线程去做处理工作。

网上的资料均指向的一个问题

    <beans:bean  >        <!--The limitation size of file is 500m。the value -1 means there is no limitation-->     
<beans:property value="500000000"/> <beans:property value="500000000"/> </beans:bean>

在配置spring MultipartResolver时不仅要配置maxUploadSize,还需要配置maxInMemorySize。但原因都没说的很清楚。只是简单说maxInMemorySize的默认值为1024 bytes(待确认),超出这个大小的文件上传spring会先将上传文件记录到临时文件中。临时文件会被删除。

我其实不是很赞同这种说法,还有说如果要在系统中读文件两次,而文件不在内存中,就会导致该问题。(已证明其实可以多次读文件,只要是单线程即可),所以我认为原因并不是出在这里,但是对于是不是加了多线程就会出错,我更加不认可。

其实这个问题,网上有位作者做了深入的研究,但是我觉得他研究的毫无意义,因为他把注意力都放到了这个问题就是一个多线程上了。有兴趣的朋友可以去看看她的博客http://www.th7.cn/Program/java/201609/956455.shtml,其实不然。正真的问题不是出在这里,而是,不应该把无关紧要的代码放到线程当中,既然这个问题,有可能是多线造成的,那么我们可以换个思路,不要去针对多线程去解决问题,而是应该避免出现这样的问题,这时候,我就想到了吧无关的代码移除到线程外边,ok。问题果然再没有出现了。移出后的Controller代码为

 1     File tmpFile = new File(filepath);
 2         final InputStream inputStream = file.getInputStream();// 直接将文件读入到刘中
 3         FileUtils.copyInputStreamToFile(inputStream, tmpFile);
 4         final Workbook wb = createworkbook(new FileInputStream(tmpFile));
 5         tmpFile.delete();// 删除本地文件
 6         threadool.execute(new Runnable() {
 7             @Override
 8             public void run() {
 9                 String[] strExcelFlag = jlpbbjService.getExcelFlag(wb);
10                 jlpbbjService.yxjlImportAndCompare(wb,
11                         Integer.valueOf(strExcelFlag[1]), type,
12                         meterCompareTask);
13                 try {
14                     inputStream.close();
15                 } catch (IOException e) {
16                     e.printStackTrace();
17                 }
18             }
19         });

 

转载于:https://www.cnblogs.com/yxh1008/p/6537863.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值