1. 概述

本文将介绍如何在 Java 中重命名或移动文件

我们会依次演示使用 NIO 的 FilesPath 类、传统的 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)上跨驱动器移动会失败
  • ✅ 仅抛出 SecurityExceptionNullPointerException

📌 总结: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() 推荐 简洁,功能完整,适合快速开发

📌 最佳实践建议:

  1. ✅ 优先使用 java.nio.file.Files.move()
  2. ✅ 配合 StandardCopyOption 控制行为(如覆盖、原子性等)
  3. ❌ 避免使用 File.renameTo(),除非你清楚它的局限
  4. ⭕ 若项目已引入 Commons IO 或 Guava,其工具类也可放心使用

所有示例代码已托管至 GitHub:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-io


原始标题:Rename or Move a File in Java