报错记录SpringBoot中MultipartFile上传报/tmp/tomcat.***.tmp (No such file or directory)

Posted DCTANT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了报错记录SpringBoot中MultipartFile上传报/tmp/tomcat.***.tmp (No such file or directory)相关的知识,希望对你有一定的参考价值。

前言

我这个接口的需求大概是用户上传一个Excel文件到后端,后端解析这个Excel,并做一系列很耗时的操作。由于这个接口很耗时,因此做成了异步处理的方式,将处理完成的信息通过消息中心告诉用户,并不是立即接口返回。然而这个接口在我本地调试的时候都是好的,上线后就报错了。报错的内容大概是:

/tmp/tomcat.**************.tmp (No such file or directory)

解决过程

很明显是文件找不到,我就去/tmp目录下找,还真的没找到这个文件,我还以为是/tmp目录下的文件会被Linux自动删除导致的报错,结果并不是这样,我在application.yaml中增加上传路径设置,改成了非/tmp目录,结果还是报错!

修改multipart file默认上传临时文件路径的方式:

spring:
  servlet:
    multipart: 
      max-file-size: 1024MB
      max-request-size: 1024MB
      enabled: true
      location: /home/test

其中的spring.servlet.multipart.location就是用来设置Tomcat上传临时文件默认路径的,改完后就会上传到这个路径下

我心想应该是解决了,结果还是报错!!报的是/home/test/upload.**************.tmp (No such file or directory)。这下我是清楚了,路径确实是改了,但是还是找不到!进入文件夹后看了一下,确实没有临时文件生成!也就是说这个问题不是因为Linux自动清除/tmp目录的文件导致的,还另有原因。

感谢这篇博客帮我找到了真实原因:

异步处理MultipartFile -- No such file or directory - 青衫执卷 - 博客园

问题解决

这个问题是异步处理导致的,即Tomcat在执行完主线程后就会把这个临时文件删除,导致后面异步线程中Excel解析的时候文件已经找不到了。解决的唯一方法就是把这个文件另存为,然后处理完了手动删除。相当于Tomcat保存一个tmp文件,我再保存一个临时文件,Tomcat在这个主线程执行完了把这个tmp文件删了就删了,而我另存为的临时文件在异步线程Excel解析完了再删除就行了,互相不冲突,然后这个bug就被我解决了。

具体代码

@PostMapping("/excelUpload")
public DataVo excelUpload(HttpServletRequest request) 
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    MultipartFile file = multipartRequest.getFile("file");

    String tmpDir = System.getProperty("java.io.tmpdir");
    if (!tmpDir.endsWith("/")) 
        tmpDir = tmpDir + "/";
    
    String tmpFileOutPath = tmpDir + UUID.randomUUID().toString() + ".tmp";
    File tmpFile = new File(tmpFileOutPath);
    int byteSize = 8192;
    byte[] bytes = new byte[byteSize];
    try 
        InputStream inputStream = file.getInputStream();
        FileOutputStream fileOutputStream = new FileOutputStream(tmpFile);
        while (true) 
            int readSize = inputStream.read(bytes);
            if (readSize == byteSize) 
                // bytes是全的
                fileOutputStream.write(bytes);
             else 
                // bytes不是全的,到文件末尾了,不足8192字节了
                if (readSize == -1) 
                    // INFO: DCTANT: 2022/2/10 如果已经是全部的,就不需要再写入了
                 else 
                    byte[] tmpByte = new byte[readSize];
                    for (int i = 0; i < readSize; i++) 
                        tmpByte[i] = bytes[i];
                    
                    fileOutputStream.write(tmpByte);
                
                fileOutputStream.flush();
                fileOutputStream.close();
                inputStream.close();
                break;
            
        
     catch (Exception e) 
        e.printStackTrace();
    

    // 为了方便理解,直接new Thread了
    new Thread(() -> 
        try 
            // 这里一段是Excel解析和执行大量业务逻辑的地方,这里就不放出了
            // 执行完业务逻辑后删除这个临时文件
            tmpFile.delete();
         catch (Exception e) 
            e.printStackTrace();
        
    ).start();
    // return什么的我省去了,大家自己写吧

主要是这个multipartFile的处理比较麻烦,如果有Hutool可以直接输出,我这边由于没用到,因此还得自己去撸这个文件导出方法,反正这个问题就通过这个方式解决了,没再报文件找不到。

=========================================================

2022年7月27日更新:

multipartFile中的输入流输出到文件其实非常非常简单,完全不需要之前说的这么复杂,multipartFile自带一个方法transferTo,入参是一个File类型目标文件,也就是说直接new File(目标路径);然后multipartFile.transferTo(file)即可!

        File localFile = new File(savePath + multipartFile.getOriginalFilename());
        try 
            multipartFile.transferTo(localFile);
         catch (IOException e) 
            e.printStackTrace();
        

其中savePath需要自己赋值

以上是关于报错记录SpringBoot中MultipartFile上传报/tmp/tomcat.***.tmp (No such file or directory)的主要内容,如果未能解决你的问题,请参考以下文章

报错记录SpringBoot中MultipartFile上传报/tmp/tomcat.***.tmp (No such file or directory)

报错记录SpringBoot中MultipartFile上传报/tmp/tomcat.***.tmp (No such file or directory)

Springboot项目中Pom.xml报错

记录springboot项目的maven的pom.xml文件第一行报错 Unknown Error

springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用

记录:springboot使用resultType报错java.lang.NullPointerException: null...亲测有效