需求是上传Excel文件并读取Excel文件中的内容,根据获取的数据执行完某些业务操作后再将一些数据写回到excel中。前台使用FormData表单的方式请求后台,后台接收类型是MultipartFile,放置文件过大时会造成内存溢出需要转换为File类型
其实转换的本质都是要创建一个file的临时文件,然后通过各种实现方式将MultipartFile中的内容写入到file中
(1)FileUtils.copyInputStreamToFile转换
package com.cxstar.file.util;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
/**
* @author zhouquan
* @description 测试MultipartFile与File互转
* @date 2023-03-12 17:31
**/
public class FileTestUtils {
/**
* MultipartFile转File
*
* 项目根路径创建临时文件,转换得到File,再删除临时文件
*
* @param multipartFile
* @return
*/
public static File multiPartFileToFile(MultipartFile multipartFile) throws IOException {
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
//获取默认定位到的当前用户目录("user.dir"),也就是当前应用的根路径
String tempDir = System.getProperty("user.dir");
//根目录下生成临时文件
File file = new File(tempDir+File.separator+originalFilename);
FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
return file;
}
}
此种方式的弊端就是需要在调用此方法后需要再手动删除,也就是要在业务代码中再掺杂删除的逻辑。
(2)multipartFile.transferTo(tempFile);
/**
* MultipartFile转File
*
* 项目根路径创建缓冲区来实现这个转换
*
* @param multipartFile
* @return
*/
public static File multiPartFileToFile2(MultipartFile multipartFile) throws IOException {
//获取文件名
String originalFilename = multipartFile.getOriginalFilename();
//获取默认定位到的当前用户目录("user.dir"),也就是当前应用的根路径
String tempDir = System.getProperty("user.dir");
//获取文件名
String filename = StringUtils.substringBeforeLast(originalFilename, ".");
//获取文件后缀
String fileExt = StringUtils.substringAfterLast(originalFilename, ".");
//在项目根路径生成临时文件
File tempFile = File.createTempFile(filename, "." + fileExt, new File(tempDir));
multipartFile.transferTo(tempFile);
//在jvm退出时执行删除此路径下的文件
tempFile.deleteOnExit();
return tempFile;
}
注意:
1.防止生成的临时文件,createTempFile()方法会在文件名后添加随机码
2.生成的文件不会立马删除,而是在jvm退出时执行删除此路径下的文件
(3)(推荐)FileUtils.writeByteArrayToFile(file, multipartFile.getBytes());
package com.cxstar.file.util;
import org.apache.commons.io.FileUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* @author zhouquan
* @description 测试MultipartFile与File互转
* @date 2023-03-12 17:31
**/
public class FileTestUtils {
/**
* MultipartFile 转 File
*
* @param multipartFile
* @throws Exception
*/
public static File multiPartFileToFile3(MultipartFile multipartFile) {
File file = null;
if (multipartFile.isEmpty()) {
return null;
}
try {
//本质上还是在项目根路径创建文件
file = new File(multipartFile.getOriginalFilename());
//将MultipartFile的byte[]写入到file中
FileUtils.writeByteArrayToFile(file, multipartFile.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return file;
}
}
此种方式相较于第二种方式,文件名不会发生改变,当然还是要手动删除
// 操作完上的文件 需要删除在根目录下生成的文件
File f = new File(sqlFile.toURI());
if (f.delete()){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
(1)File转MultipartFile
MultipartFile文件上传时,其实springmvc已经转为StandardMultipartFile子类型
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile
MultipartFile是一个接口,因此转成MultipartFile格式需要转成实现MultipartFile接口的实现类即可
package com.cxstar.file.util;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileInputStream;
/**
* @author zhouquan
* @description 测试MultipartFile与File互转
* @date 2023-03-12 17:31
**/
public class FileTestUtils {
public static MultipartFile getMultipartFile(File file) throws Exception {
MultipartFile multipartFile = new MockMultipartFile(file.getName(), new FileInputStream(file));
return multipartFile;
}
@PostMapping(value = "/uploadSql")
@Operation(summary = "全部查询接口表SQL信息", description = "全部查询接口表SQL信息")
public ApiResponse<InterfaceSql> uploadSql(@RequestParam("file") MultipartFile file) {
return interfaceSqlAppService.uploadSql(file);
}
public DomainResponse<InterfaceSql> uploadSql(MultipartFile file) {
if (file.isEmpty()) {
throw new YTRuntimeException("上传失败,请选择文件");
}
File sqlFile = null;
try {
//本质上还是在项目根路径创建文件
sqlFile = new File(file.getOriginalFilename());
//将MultipartFile的byte[]写入到file中
FileUtils.writeByteArrayToFile(sqlFile, file.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
String fileName = file.getOriginalFilename();
StringBuilder fileContent = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(sqlFile))) {
String line;
while ((line = br.readLine()) != null) {
fileContent.append(line).append("\n");
}
} catch (IOException e) {
throw new YTRuntimeException("读取文件失败");
}
String sqlContent = fileContent.toString();
InterfaceSql interfaceSql = new InterfaceSql();
interfaceSql.setFileName(fileName);
interfaceSql.setFileContent(sqlContent);
interfaceSqlRepo.create(interfaceSql);
// 操作完上的文件 需要删除在根目录下生成的文件
File f = new File(sqlFile.toURI());
if (f.delete()){
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
return DomainResponse.ok(interfaceSql);
}
@GetMapping(value = "/downloadSql/{INTERFACE_SQL_id}")
@Operation(summary = "全部查询接口表SQL信息", description = "全部查询接口表SQL信息")
public ApiResponse<Void> downloadSql(@PathVariable("INTERFACE_SQL_id") String id, HttpServletResponse response) {
return interfaceSqlAppService.downloadSql(id,response);
}
public DomainResponse<Void> downloadSql(String id,HttpServletResponse response) {
InterfaceSql interfaceSql = interfaceSqlRepo.queryById(id);
String fileName = interfaceSql.getFileName();
String fileContent = interfaceSql.getFileContent();
try {
FileUDUtil.downloadDbData(response,fileName,fileContent);
} catch (Exception e) {
throw new RuntimeException(e);
}
return DomainResponse.ok();
}
public static void downloadDbData(HttpServletResponse response, String fileName, String fileContent) throws IOException {
if (ObjectUtil.isEmpty(fileName)) {
throw new YTRuntimeException("文件名称不允许为空");
}
try {
// 创建File对象
File file = new File(fileName);
// 创建FileOutputStream和BufferedOutputStream
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 将字符串内容写入文件
bos.write(fileContent.getBytes());
// 关闭流
bos.close();
fos.close();
// 设置响应头
response.setHeader("Content-Disposition", "attachment;filename="+fileName);
// 获取OutputStream对象
OutputStream os = response.getOutputStream();
// 创建FileInputStream和byte数组
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
// 将文件内容写入到客户端
int len;
while ((len = fis.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
// 关闭流
fis.close();
os.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}