java.lang.IllegalStateException: File has already been moved - cannot be transferred again

Xavier DSouza picture Xavier DSouza · Apr 16, 2013 · Viewed 12.1k times · Source

I am trying to upload a file and save it on server. But I get:

java.lang.IllegalStateException: File has already been moved - cannot be transferred again

I am using Commons FileUpload jar(CommonsMultipartFile). I get IllegalStateException for statement : user.getFileData().transferTo(new File("/home/xavier/uploads/" + user.getFileData().getOriginalFilename()));

Here user is the bean. It worked for me initially but when I tested again by deleting the files from uploads folder it threw exception as above.

Stacktrace:

java.lang.IllegalStateException: File has already been moved - cannot be transferred again
    at org.springframework.web.multipart.commons.CommonsMultipartFile.transferTo(CommonsMultipartFile.java:126)
    at com.raistudies.controllers.RegistrationController.processForm(RegistrationController.java:113)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
    at java.lang.Thread.run(Thread.java:722)

Answer

Arosha picture Arosha · Jun 21, 2014

The exception you reference in your question states: "File has been moved - cannot be read again". This is because we are trying to read inputstream more than one time from multipart file.

I also faced this issue at one time, and in my case, first I validated the content of the file, and after that I tried to save it using "transferTo" method in Spring MultiPart. This exception comes when I try to use "transferTo" method. Here I am calling for inputstream twice.

I do not face this issue when file size is too small. In "transferTo" method there is an internal call for "isAvailable" method. Please follow the code segment below:

protected boolean More ...isAvailable() {
        // If in memory, it's available.
    if (this.fileItem.isInMemory()) {
        return true;
    }
    // Check actual existence of temporary file.
    if (this.fileItem instanceof DiskFileItem) {
        return ((DiskFileItem) this.fileItem).getStoreLocation().exists();
    }
    // Check whether current file size is different than original one.
    return (this.fileItem.getSize() == this.size);
}

link: http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-web/3.2.1.RELEASE/org/springframework/web/multipart/commons/CommonsMultipartFile.java#CommonsMultipartFile.isAvailable%28%29

Observations:

If it is too small, spring save it in memory and when we ask for the file it retrive from memory. We can ask for it multiple times because file is in memory.

If it is large enough, Spring will save it as a temporary file which we do not know the location, but after we read inputstream once that file may be deleted internally by Spring. Then when we ask for the second time that error says "cannot be read again".

So my solution is first I have to save it in server loaction using "transferTo" method and retrive that local file to validate or any other second time need.

I think it is not good to increase "maxUploadSize" in "multipartResolver" bean as it consumes more memory if the file is too large.