简体   繁体   中英

java.io.FileNotFoundException for a present MultipartFile

I am dealing with a strange behaviour regarding a MultipartFile.

My project is a Spring Boot backend that receives a text file. This text file comes in as a MultipartFile. I than want to send this file to a secondary Spring Boot backend which shall add some content to the file, before my primary backend reads the file. These content changes are not mandatory, the program does not crash if they are not present.

To send the MultipartFile to the other backend I have to convert the MultipartFile to a java.io.File. And while doing this somehow the MultipartFile gets destroyed.

After creating a java.io.File the original MultipartFile cannot be read by the BufferedReader.

Heavy edit:

My projects specifications changed and the extra backend was cancelled. However I am still curious what happens here. The following code reproduces the Exception I encountered:

@CrossOrigin
@RestController
@RequestMapping("/dragon")
public class TestController {

    @PostMapping("/killFile")
    public String sendInFileHere(@Valid @RequestBody MultipartFile multipartFile) {
        if (multipartFile == null) {
            throw new IllegalArgumentException("File has to be Present");
        }
        File file = new File(multipartFile.getOriginalFilename());
        try {
            multipartFile.transferTo(file);
        } catch (IOException e) {
            e.printStackTrace();
        }
        BufferedReader reader;
        try {
            InputStream is = multipartFile.getInputStream(); //exception is thrown here
            reader = new BufferedReader(new InputStreamReader(is));
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "something went wrong";
    }
}

The exception that is thrown is as follws:

java.io.FileNotFoundException: C:\Users\lucas.kahler\AppData\Local\Temp\tomcat.1947057742180166642.8080\work\Tomcat\localhost\ROOT\upload_51753fdf_0308_49d4_800c_bd95bd7760f3_00000001.tmp (Das System kann die angegebene Datei nicht finden)
    at java.base/java.io.FileInputStream.open0(Native Method)
    at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
    at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:194)
    at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:251)
    at eu.molit.dragon.text.Test.sendInFileHere(Test.java:34)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:526)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1591)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:835)

When I comment out the part, where the file receives the content from the MultipartFile it perfectly works:

@CrossOrigin
@RestController
@RequestMapping("/dragon")
public class TestController {

    @PostMapping("/killFile")
    public String sendInFileHere(@Valid @RequestBody MultipartFile multipartFile) {
        if (multipartFile == null) {
            throw new IllegalArgumentException("File has to be Present");
        }
        File file = new File(multipartFile.getOriginalFilename());
//        try {
//            multipartFile.transferTo(file);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        BufferedReader reader;
        try {
            InputStream is = multipartFile.getInputStream(); 
            reader = new BufferedReader(new InputStreamReader(is));
            return reader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "something went wrong";
    }
}

In the above example the first line of the sent text file is returned. That indicates that something is happening during the conversion from MultipartFile to File.

Any ideas?

This is normal behaviour.

The call to transferTo consumes the associated InputStream. As a result, you can't re-use it.

If you want to re-read the data, you will have to do it against your newly created (and written) File , by opening a stream against it.

I got similar problem ( java.io.FileNotFoundException ) when using asynchronous thread to get InputStream , sample code as below:

@CrossOrigin
@RestController
@RequestMapping("/dragon")
public class TestController {

    // http thread
    @PostMapping("/killFile")
    public String sendInFileHere(@Valid @RequestBody MultipartFile multipartFile) {
        if (multipartFile == null) {
            throw new IllegalArgumentException("File has to be Present");
        }

        // create a new thread to handle InputStream
        new Thread(() -> {
            try {
                // simulate some time comsuming tasks...
                Thread.sleep(1000);

                InputStream stream = multipartFile.getInputStream(); // exception will be thrown when invoking this line after http thread returns.
                // do something with InputStream...
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        // http thread returns
        return "Task submited.";
    }
}

Just as above example, when the http thread returns, it's impossible to get the InputStream from MultipartFile anymore. If you do need to handle stream asynchronously, please cache the InputStream before http thread ends, for later usage:

        // get the InputStream here
        InputStream stream = multipartFile.getInputStream();
        new Thread(() -> {
            try {
                // simulate some time comsuming tasks...
                Thread.sleep(1000);

                // stream is available here
                // do something with InputStream...
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM