首页 > 编程语言 >MultipartFile上传文件异步处理时的java.io.FileNotFoundException

MultipartFile上传文件异步处理时的java.io.FileNotFoundException

时间:2022-08-16 17:34:48浏览次数:66  
标签:文件 java FileNotFoundException Word io Pdf MultipartFile 上传

参考:https://javajgs.com/archives/26157

一.背景

1-1 需求

前端上传Word文档,后端将接收到的Word文档①上传到文件服务器②将Word转为Pdf。

1-2 方案

因为Word转Pdf的耗时较长,为了及时给到前端返回信息,在将文件上传到文件服务器后,异步将Word转为Pdf。

二.实现

创建一个SpringBoot项目。

 1 package com.trent.upload.action;
 2 
 3 import com.trent.upload.service.UploadService;
 4 import org.springframework.web.bind.annotation.PostMapping;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RestController;
 7 import org.springframework.web.multipart.MultipartFile;
 8 
 9 import javax.annotation.Resource;
10 
11 /**
12  * 上传文件的Action层
13  *
14  * @author Hutao
15  * @date 2022/8/16 15:10
16  * @since 1.0
17  */
18 @RequestMapping
19 @RestController
20 public class UploadAction {
21 
22     @Resource
23     private UploadService uploadService;
24 
25     /**
26      * 文件上传接口
27      * @param multipartFile 上传的文件
28      * @return 上传结果
29      *
30      * @author Hutao
31      * @date 2022/8/16 15:10
32      * @since 1.0
33      */
34     @PostMapping("/upload")
35     public String upload(MultipartFile multipartFile) {
36 
37         uploadService.dealFile(multipartFile);
38         return "上传成功";
39     }
40 }

 

 1 package com.trent.upload.service;
 2 
 3 import org.springframework.stereotype.Service;
 4 import org.springframework.web.multipart.MultipartFile;
 5 
 6 import java.util.concurrent.ExecutorService;
 7 import java.util.concurrent.Executors;
 8 import java.util.concurrent.TimeUnit;
 9 
10 /**
11  * 上传文件的Service层
12  *
13  * @author Hutao
14  * @date 2022/8/16 15:11
15  * @since 1.0
16  */
17 @Service
18 public class UploadService {
19 
20     /**
21      * 线程池(仅用于简单演示)
22      */
23     private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
24 
25     /**
26      * 处理上传的文件
27      * @param multipartFile 上传的文件
28      *
29      * @author Hutao
30      * @date 2022/8/16 15:13
31      * @since 1.0
32      */
33     public void dealFile(MultipartFile multipartFile) {
34         // 模拟上传Word文件到文件服务器
35         System.out.println("上传Word文件到文件服务器");
36 
37         // 异步将Word文件转为Pdf
38         EXECUTOR_SERVICE.execute(() -> convertToPdf(multipartFile));
39     }
40 
41     /**
42      * 将文件转为Pdf
43      * @param multipartFile 待转换的源文件
44      *
45      * @author Hutao
46      * @date 2022/8/16 15:13
47      * @since 1.0
48      */
49     public void convertToPdf(MultipartFile multipartFile) {
50         try {
51             
52             // 获取上传的文件的输入流,用于转为Pdf,如果成功获取到了输入流,就认为转Pdf成功
53             multipartFile.getInputStream();
54             System.out.println("Word转Pdf成功");
55 
56         } catch (Exception e) {
57             System.out.println("Word转Pdf失败");
58             e.printStackTrace();
59         }
60     }
61 }

三.问题

3-1 问题描述

以上是一个简单的演示,在实际的项目中,会偶现如下异常。

上传Word文件到文件服务器
Word转Pdf失败
java.io.FileNotFoundException: C:\Users\Liujl\AppData\Local\Temp\tomcat.8080.567748920478140755\work\Tomcat\localhost\ROOT\upload_8e27d0a7_9cf4_4f8a_aecc_ea051653749e_00000006.tmp (系统找不到指定的文件。)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:198)
    at org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)
    at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.getInputStream(StandardMultipartHttpServletRequest.java:254)
    at com.trent.upload.service.UploadService.convertToPdf(UploadService.java:57)
    at com.trent.upload.service.UploadService.lambda$dealFile$0(UploadService.java:43)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

意思是找不到某个临时文件。

3-2 问题复现

在UploadService类的51行添加如下代码,可保证每次上传文件操作都会出现3-1中的异常。

 1     public void convertToPdf(MultipartFile multipartFile) {
 2         try {
 3             TimeUnit.MILLISECONDS.sleep(10);
 4             // 获取上传的文件的输入流,用于转为Pdf,如果成功获取到了输入流,就认为转Pdf成功
 5             multipartFile.getInputStream();
 6             System.out.println("Word转Pdf成功");
 7 
 8         } catch (Exception e) {
 9             System.out.println("Word转Pdf失败");
10             e.printStackTrace();
11         }
12     }

3-3 原因分析

1.后台用MultipartFile接收到前端传来的文件后,会在本地生成一个临时文件,以.tmp结尾;

2.MultipartFile对应的临时文件的生命周期是一个请求会话,会话结束,MultipartFile的临时文件会被自动清理;

3.因为将文件转为Pdf的方法是在请求主线程之外的另一个线程中执行的,所以不在请求会话的生命周期内。如果请求会话的主线程结束了(将请求结果返回给前端了),这个请求传来的MultipartFile的临时文件就会被清理掉,在将文件转Pdf的线程中就拿不到MultipartFile对应的临时文件,也就获取不到对应的输入流,故抛出FileNotFoundException。

四.解决方案

主线程在用MultipartFile接收到前端传来文件后,立即将MultipartFile保存为本地文件。将文件转Pdf时,使用保存在本地的文件,转换完成后,删除本地文件。

注:

1.可使用MultipartFile的transferTo方法将MultipargFile转为本地文件,但需要注意,transferTo方法被调用后,也会删除MultipartFile对应的临时文件;

2.在使用transferTo的时候可能会出现绝对路径和相对路径的问题;

3.鉴于1.2中transferTo方法的局限性,建议手动获取MultipartFile的输入流,然后写到本地文件中。可以使用Hutool的FileUtils.copyInputStreamToFile(final InputStream source, final File destination)方法;

4.本地文件使用完成后,务必删除本地文件,避免服务器硬盘被占满。

标签:文件,java,FileNotFoundException,Word,io,Pdf,MultipartFile,上传
From: https://www.cnblogs.com/certainTao/p/16591869.html

相关文章

  • Java安装卸载
    Java基本知识JDKJavaDevelopmentKit开发工具包JREJavaRuntimeEnvironment运行环境JVMJavaVirtualMachine虚拟机Java开发环境搭建JDK下载与安装搜索J......
  • java如何判断一个对象是否死去
    简单直观的一个方法是:对一个对象添加引用计数器。每当有地方引用它时,计数器的值加1;当引用失效时,计数器de的值减1.而当计数器的值为0时这个对象就不会再被使用,判断为已......
  • JavaDoc
    JavaDocJavaDoc是一种将注释生成HTML文档的技术,生成的HTML文档类似于Java的API,易读且清晰明了。只要在编写程序时以一套特定的标签作注释,在程序编写完成后,通过Javadoc就......
  • JS-Symbol(javascript的第七种数据类型)
    introduce在ES5中对象的属性名都是字符串,这容易造成属性名的冲突。引入Symbol类型来解决命名冲突的问题。Symbol的值通过Symbol函数来生成,也就是说,对象的属性名......
  • java中获取指定日期是周几
    可以使用Calendar日历工具类获取,代码如下:Calendarcalendar=Calendar.getInstance();calendar.setTime(newDate());intindex=calendar.get(Calendar.DAY_OF_WEEK)-......
  • JavaSE:第十三章:一分钟了解反射
    首先分享一篇关于反射的博文,因为我发现这篇博文写的很详细,然后开始我的表演:首先学习反射之前,我要提出疑问:反射是个什么东西?它是用来做什么的?平时的应用场景有哪些?为啥......
  • MobaXterm链接linux虚拟机报错Network error: Connection refused
    原文链接使用虚拟机安装Ubuntu,然后在Windows下使用MobaXterm链接。若出现如下报错:Networkerror:Connectionrefused需要安装openssh:sudoaptinstallopens......
  • 【JAVA】URL编码对照表
    转载:https://blog.csdn.net/Danalee_Py/article/details/108083038?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlog......
  • javascript实现前端sleep
    一、定义//第一种,使用while循环functionsleep(delay){varstart=(newDate()).getTime();while((newDate()).getTime()-start<delay){con......
  • 高效能团队的Java研发规范(进阶版)
    目前大部分团队是使用的阿里巴巴Java开发规范,不过在日常开发中难免遇到覆盖不到的场景,本文在阿里巴巴Java开发规范基础上,补充一些常用的规范,用于提升代码质量及增强代码可......