Spring文件上传报错:java.lang.IllegalStateException: File has been moved - cannot be read again
1.问题描述
在使用spring开发文件上传接口的时候,后端使用线程异步读取文件,本地测试代码没问题,当系统部署到服务器进行测试时,如果文件稍大,就会出现以下错误:
java.lang.IllegalStateException: File has been moved - cannot be read again
2.可能原因
spring文件上传,一般都是使用的multipartResolver组件,这个组件的配置项里面有两个配置
-
maxUploadSize:限制上传文件大小,单位bytes
-
maxInMemorySize:限制保存上传文件的缓存的大小,单位bytes,默认10240(10k)
上传规则是这样的,当文件大小超过maxUploadSize设置时,spring会直接拦截,不给上传文件。当上传文件大小在maxUploadSize要求内时,文件会被上传,此时会再使用maxInMemorySize配置大小跟上传文件的大小做比较,如果文件大小大于了maxInMemorySize了,那么这个文件就不会被写入内存,而是会被写入到临时文件里面。那么这里就有问题了,写入到临时文件的文件,不知道啥时候会被删除掉,也可能刚写进去就被删除了,当文件被删除后,系统再想读取文件,就会报错:File has been moved - cannot be read again
但是在单线程执行接口且没有设置maxInMemorySize的时候,并不会出现以上的问题,只有在多线程执行的时候,会出现这样的问题。
猜测可能原因是这样:多线程读取文件的时候,GC进程判断主进程目前没有对文件进行强引用,就直接把文件删除了,导致多线程读取不到临时文件夹的文件。
3.解决方法
MultipartResolver组件在设置maxUploadSize的时候,顺便设置一下maxInMemorySize的值,最好是两个配置项值保持一致,这样上传的文件能保证在内存中,这样多线程情况下也可以读取到文件了。
这个方法可以解决多线程下大文件读取不到的问题,但是具体为什么读取不到,还需要继续研究一下。