在Java开发中,处理文件上传和下载是常见的任务。而在Spring框架中,MultipartFile是处理文件上传的常用类,它提供了方便的方法来操作上传的文件。但有时候我们需要在不同的场景中进行文件类型的转换,比如将File类型转换为MultipartFile类型或者将MultipartFile类型转换为File类型。本文将介绍一种使用IO流实现File和MultipartFile文件类型之间的互转的方法,并且解决了一些已知的问题和限制。
前言
在实际开发中,常见的文件类型转换方法有两种:
- 使用
CommonsMultipartFile
(在Spring Web 6中被废弃,同时又与Spring Boot 3冲突)- 使用
org.springframework.mock.web.MockMultipartFile
转换(一般生产环境不使用这个方法)
然而,在某些情况下,这些方法可能并不适用。因此,本文提供了第三种方法,通过自定义实现来完成File和MultipartFile之间的互转。
方案
我们提供了一个名为MyFileUtil
的工具类,其中包含了两个静态方法:
fileToMultipartFile(File file, String fieldName)
:将File类型转换为MultipartFile类型。multipartFileToFile(MultipartFile multipartFile)
:将MultipartFile类型转换为File类型。
实现细节
以下是具体的实现细节:
File转MultipartFile
public static MultipartFile fileToMultipartFile(File file, String fieldName) throws IOException {
try {
if (file == null || !file.exists()) {
throw new FileNotFoundException("文件未找到:" + file);
}
byte[] content = Files.readAllBytes(file.toPath());
return new ByteArrayMultipartFile(content, file.getName(), fieldName, Files.probeContentType(file.toPath()));
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 删除临时文件
file.delete();
}
}
该方法首先读取文件的内容到一个字节数组中,然后利用自定义的ByteArrayMultipartFile
类构造一个MultipartFile对象,并返回。
MultipartFile转File
public static File multipartFileToFile(MultipartFile multipartFile) throws IOException {
if (multipartFile.isEmpty()) {
throw new IOException("传入的MultipartFile为空");
}
String originalFilename = multipartFile.getOriginalFilename();
String tempFileSuffix = originalFilename != null ? originalFilename.substring(originalFilename.lastIndexOf('.')) : ".tmp";
File tempFile = File.createTempFile("temp", tempFileSuffix);
try (InputStream ins = multipartFile.getInputStream();
OutputStream os = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = ins.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
return tempFile;
}
MyFileUtil完整代码
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Files;
/**
* @author RainbowCloud
*/
public class MyFileUtil {
/**
* 将 File 转换为 MultipartFile。
*
* @param file 要转换的文件
* @param fieldName 字段名,通常用于表单中的文件字段名
* @return 转换后的 MultipartFile
* @throws IOException 如果发生I/O错误
*/
public static MultipartFile fileToMultipartFile(File file, String fieldName) throws IOException {
try {
if (file == null || !file.exists()) {
throw new FileNotFoundException("文件未找到:" + file);
}
byte[] content = Files.readAllBytes(file.toPath());
return new ByteArrayMultipartFile(content, file.getName(), fieldName, Files.probeContentType(file.toPath()));
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 删除临时文件
file.delete();
}
}
/**
* 将 MultipartFile 转换为 File。
*
* @param multipartFile 要转换的 MultipartFile
* @return 转换后的 File
* @throws IOException 如果发生I/O错误
*/
public static File multipartFileToFile(MultipartFile multipartFile) throws IOException {
if (multipartFile.isEmpty()) {
throw new IOException("传入的MultipartFile为空");
}
String originalFilename = multipartFile.getOriginalFilename();
String tempFileSuffix = originalFilename != null ? originalFilename.substring(originalFilename.lastIndexOf('.')) : ".tmp";
File tempFile = File.createTempFile("temp", tempFileSuffix);
try (InputStream ins = multipartFile.getInputStream();
OutputStream os = new FileOutputStream(tempFile)) {
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = ins.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
}
return tempFile;
}
/**
* 内置一个简单的 MultipartFile 实现类,用于File转换
*/
private static class ByteArrayMultipartFile implements MultipartFile {
private final byte[] content;
private final String name;
private final String originalFilename;
private final String contentType;
/**
* 构造函数
*
* @param content 文件内容
* @param originalFilename 文件原始名字
* @param name 字段名
* @param contentType 文件类型
*/
public ByteArrayMultipartFile(byte[] content, String originalFilename, String name, String contentType) {
this.content = content;
this.originalFilename = originalFilename;
this.name = name;
this.contentType = contentType;
}
@Override
public String getName() {
return this.name;
}
@Override
public String getOriginalFilename() {
return this.originalFilename;
}
@Override
public String getContentType() {
return this.contentType;
}
@Override
public boolean isEmpty() {
return (this.content == null || this.content.length == 0);
}
@Override
public long getSize() {
return this.content.length;
}
@Override
public byte[] getBytes() {
return this.content;
}
@Override
public InputStream getInputStream() {
return new ByteArrayInputStream(this.content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
try (OutputStream os = new FileOutputStream(dest)) {
os.write(this.content);
}
}
}
}
结语
通过本文介绍的方法,我们可以方便地在File和MultipartFile之间进行转换,并且避免了一些已知的问题和限制。这种方法在各种场景下都可以适用,并且不依赖于特定的框架版本或者环境。希望这篇文章对你有所帮助!