不管是在项目中还是日常需求,我们总是有操作文件数据的需求,Java中操作文件不可避免就要使用File类,而Spring中为我们提供了一个操作文件的接口,通过该接口我们可以获取用户上传的文件对象并写入文件系统中。
前言
一、File类
二、MultipartFile接口
2.1 源码和方法功能
2.2 void transferTo(File dest)
CommonsMultipartFile中的方法体
StandardMultipartHttpServletRequest实现类
2.3 default void transferTo(Path dest)
总结
java.io.File是 Java 标准库中用于操作文件和目录路径的类。它提供了很多方法,用于创建、删除、重命名、判断文件是否存在、获取文件信息等操作。
获取文件信息
boolean exists()
: 判断文件或目录是否存在。boolean isFile()
: 判断是否是文件。boolean isDirectory()
: 判断是否是目录。String getName()
: 获取文件或目录的名称。String getPath()
: 获取文件或目录的路径。String getAbsolutePath()
: 获取文件或目录的绝对路径。long length()
: 获取文件的大小(字节数)。文件和目录操作
boolean createNewFile()
: 创建新文件。如果文件已存在,则不创建,返回 false
。boolean mkdir()
: 创建新目录。如果目录已存在,则不创建,返回 false
。boolean mkdirs()
: 创建新目录及其父目录,如果不存在的话。boolean delete()
: 删除文件或目录。文件路径操作
boolean renameTo(File dest)
: 重命名文件或目录。如果成功,返回 true
;否则,返回 false
。String[] list()
: 返回目录下的文件和目录名数组。File[] listFiles()
: 返回目录下的文件和目录的 File
对象数组。文件过滤
String[] list(FilenameFilter filter)
: 返回目录下满足指定过滤器条件的文件和目录名数组。File[] listFiles(FileFilter filter)
: 返回目录下满足指定过滤器条件的文件和目录的 File
对象数组。 MultipartFile是 Spring 框架提供的一个接口,用于表示处理文件上传的对象。它通常用于处理multipart/form-data
类型的请求,例如处理文件上传的表单。首先我们依旧可以通过源码的学习来进一步了解这个接口。
public interface MultipartFile extends InputStreamSource {
String getName();
@Nullable
String getOriginalFilename();
@Nullable
String getContentType();
boolean isEmpty();
long getSize();
byte[] getBytes() throws IOException;
InputStream getInputStream() throws IOException;
default Resource getResource() {
return new MultipartFileResource(this);
}
void transferTo(File dest) throws IOException, IllegalStateException;
default void transferTo(Path dest) throws IOException, IllegalStateException {
FileCopyUtils.copy(this.getInputStream(), Files.newOutputStream(dest));
}
}
MultipartFile
封装成了 Resource
对象,从而可以使用 Resource
接口提供的方法来操作上传文件的内容。前面我们已经介绍了该方法是Spring中提供的将上传文件保存到指定的文件中的抽象方法,溯源源码我们可以看到这个接口方法被三个实现类实现了,分别是CommonsMultipartFile、MockMultipartFile 和 StandardMultipartHttpServletRequest。
我们可以看到CommonsMultipartFile中的方法体主要是通过检测传进来的文件是否可用、是否存在,并在检测完成就执行写入的操作
public void transferTo(File dest) throws IOException, IllegalStateException {
if (!this.isAvailable()) {
throw new IllegalStateException("File has already been moved - cannot be transferred again");
} else if (dest.exists() && !dest.delete()) {
throw new IOException("Destination file [" + dest.getAbsolutePath() + "] already exists and could not be deleted");
} else {
try {
this.fileItem.write(dest);
LogFormatUtils.traceDebug(logger, (traceOn) -> {
String action = "transferred";
if (!this.fileItem.isInMemory()) {
action = this.isAvailable() ? "copied" : "moved";
}
return "Part '" + this.getName() + "', filename '" + this.getOriginalFilename() + "'" + (traceOn ? ", stored " + this.getStorageDescription() : "") + ": " + action + " to [" + dest.getAbsolutePath() + "]";
});
} catch (FileUploadException var3) {
throw new IllegalStateException(var3.getMessage(), var3);
} catch (IOException | IllegalStateException var4) {
throw var4;
} catch (Exception var5) {
throw new IOException("File transfer failed", var5);
}
}
}
上面这段demo中可能对于this.isAvailable()有疑问,我们知晓这里的this其实是该类的实例化对象,但是这里的this.isAvailable()就是拿来判断目的文件是否可用,调用的就是类的内部方法,判断是否可用的条件就是该目标文件是否被加载进内存中!
这里给出一个使用该方法的例子,需要注意的是这时候方法要求的是一个目标File对象,我们需要在调用该目标方法的时候就根据目标路径创建了目标的File对象。
// 获取上传文件的原始文件名
String originalFilename = StringUtils.cleanPath(file.getOriginalFilename());
// 构建目标文件对象
File destFile = new File("/path/to/destination/directory", originalFilename);
try {
// 将上传文件保存到目标文件
file.transferTo(destFile);
return "File uploaded successfully!";
} catch (IOException e) {
e.printStackTrace();
return "Failed to upload the file.";
}
而另一个实现类StandardMultipartHttpServletRequest和CommonsMultipartFile的区别就在于使用StandardMultipartHttpServletRequest直接上传文件的话可能会出现目录跳跃的问题,而CommonsMultipartFile不会,这是因为其对路劲分隔符了相关的限制,具体的部分大家可以看看这篇博客:https://www.cnblogs.com/zpchcbd/p/17148291.html 而MockMultipartFile这个实现类就更简单了,做了简单的输入输出流的copy,这里就不再水字数了。
该默认方法在实现类中被重写了,但主要的功能还是不变,就是将上传的文件写入到指定路径的Path对象中实现文件上传的功能。
这里给出使用的示例代码:
// 构建目标文件路径
String uploadDirectory = "/path/to/destination/directory";
String originalFilename = file.getOriginalFilename();
Path filePath = Paths.get(uploadDirectory, originalFilename);
try {
// 将上传文件保存到目标文件
file.transferTo(filePath);
return "File uploaded successfully!";
} catch (IOException e) {
e.printStackTrace();
return "Failed to upload the file.";
}
这篇文章主要围绕MultipartFile接口和File类中相关方法的功能进行梳理,其中有关文件写入File对象和Path对象重点进行了剖析,而具体的有关文件管理的部分知识大家可以关注后续荔枝梳理的有关SpringBoot整合MinIO的博客和后续的博文输出。希望能帮助到有需要的小伙伴~~~
今朝已然成为过去,明日依然向往未来!我是荔枝,在技术成长之路上与您相伴~~~
如果博文对您有帮助的话,可以给荔枝一键三连嘿,您的支持和鼓励是荔枝最大的动力!
如果博文内容有误,也欢迎各位大佬在下方评论区批评指正!!!