1. 概述
本文将介绍如何在 Java 中重命名或移动文件。
我们会依次演示使用 NIO 的 Files
和 Path
类、传统的 File
类、Google Guava 以及 Apache Commons IO 库来完成这一操作。
本文属于 Baeldung 系列教程 “Java – 回归基础” 的一部分。
2. 环境准备
以下示例中,我们定义两个常量分别表示源文件路径和目标文件路径,并通过 JUnit 的 @BeforeEach
和 @AfterEach
注解确保测试可重复执行:
private final String FILE_TO_MOVE = "src/test/resources/originalFileToMove.txt";
private final String TARGET_FILE = "src/test/resources/targetFileToMove.txt";
@BeforeEach
public void createFileToMove() throws IOException {
File fileToMove = new File(FILE_TO_MOVE);
fileToMove.createNewFile();
}
@AfterEach
public void cleanUpFiles() {
File targetFile = new File(TARGET_FILE);
targetFile.delete();
}
✅ 上述代码确保每次测试前创建源文件,测试后清理目标文件,避免干扰下一次运行。
3. 使用 NIO 的 Paths 和 Files 类
推荐方式:使用 Files.move()
方法,这是 Java 7 引入 NIO.2 后的首选方案。
@Test
public void givenUsingNio_whenMovingFile_thenCorrect() throws IOException {
Path fileToMovePath = Paths.get(FILE_TO_MOVE);
Path targetPath = Paths.get(TARGET_FILE);
Files.move(fileToMovePath, targetPath);
}
⚠️ 注意事项:
- ✅ 源文件必须存在
- ✅ 目标目录必须存在(否则抛
NoSuchFileException
) - ❌ 不会自动创建缺失的父目录
- ⚠️ 若目标文件已存在,默认行为取决于平台,通常会抛异常(可通过
StandardCopyOption.REPLACE_EXISTING
控制)
💡 Files.move()
支持多种选项,例如:
Files.move(source, target, StandardCopyOption.REPLACE_EXISTING);
这是目前最标准、最健壮的方式,✅ 建议优先使用。
4. 使用 File 类的 renameTo 方法
传统方式:调用 File.renameTo()
。
@Test
public void givenUsingFileClass_whenMovingFile_thenCorrect() throws IOException {
File fileToMove = new File(FILE_TO_MOVE);
boolean isMoved = fileToMove.renameTo(new File(TARGET_FILE));
if (!isMoved) {
throw new FileSystemException(TARGET_FILE);
}
}
⚠️ 踩坑警告:
- ❌ 方法返回 boolean 而非抛出异常,失败时静默返回
false
- ❌ 失败原因不明确(跨文件系统、权限、目标已存在等都可能导致失败)
- ❌ 在某些操作系统(如 Windows)上跨驱动器移动会失败
- ✅ 仅抛出
SecurityException
和NullPointerException
📌 总结:renameTo()
行为不稳定,不推荐用于生产环境,仅适合简单场景或遗留系统维护。
5. 使用 Guava
Google Guava 提供了更友好的封装:
@Test
public void givenUsingGuava_whenMovingFile_thenCorrect()
throws IOException {
File fileToMove = new File(FILE_TO_MOVE);
File targetFile = new File(TARGET_FILE);
com.google.common.io.Files.move(fileToMove, targetFile);
}
✅ 优点:
- 简洁易读
- 自动抛出
IOException
,避免判断返回值 - 内部做了跨平台兼容处理
⚠️ 缺点:
- 需引入 Guava 依赖(较大)
com.google.common.io.Files
容易与 JDK 自带类混淆
📌 适合已在使用 Guava 的项目,否则没必要单独引入。
6. 使用 Commons IO
Apache Commons IO 提供了最简单直接的 API:
@Test
public void givenUsingApache_whenMovingFile_thenCorrect() throws IOException {
FileUtils.moveFile(FileUtils.getFile(FILE_TO_MOVE), FileUtils.getFile(TARGET_FILE));
}
✅ 这一行代码既能重命名也能移动文件,逻辑统一。
更进一步,它还支持自动创建目标目录:
@Test
public void givenUsingApache_whenMovingFileApproach2_thenCorrect() throws IOException {
FileUtils.moveFileToDirectory(
FileUtils.getFile("src/test/resources/fileToMove.txt"),
FileUtils.getFile("src/main/resources/"), true);
}
📌 参数说明:
- 第三个参数
true
表示允许自动创建目标目录
✅ 优势:
- API 设计清晰
- 自动处理常见边界情况
- 社区广泛使用,稳定性高
💡 推荐指数:⭐⭐⭐⭐☆(仅次于 NIO)
7. 总结
方式 | 是否推荐 | 说明 |
---|---|---|
✅ NIO Files.move() |
强烈推荐 | 标准化、健壮、可控性强 |
❌ File.renameTo() |
不推荐 | 行为不可靠,错误不透明 |
⭕ Guava Files.move() |
可选 | 项目已用 Guava 时可考虑 |
⭕ Commons IO FileUtils.moveFile() |
推荐 | 简洁,功能完整,适合快速开发 |
📌 最佳实践建议:
- ✅ 优先使用
java.nio.file.Files.move()
- ✅ 配合
StandardCopyOption
控制行为(如覆盖、原子性等) - ❌ 避免使用
File.renameTo()
,除非你清楚它的局限 - ⭕ 若项目已引入 Commons IO 或 Guava,其工具类也可放心使用
所有示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-io