Reliable File.renameTo() alternative on Windows?

2022-08-31 10:30:34

Java是有问题的,特别是在Windows上,看起来。正如 API 文档所说,File.renameTo()

此方法行为的许多方面本质上都依赖于平台:重命名操作可能无法将文件从一个文件系统移动到另一个文件系统,它可能不是原子的,并且如果目标抽象路径名已存在,则它可能不会成功。应始终检查返回值,以确保重命名操作成功。

在我的情况下,作为升级过程的一部分,我需要移动(重命名)可能包含千兆字节数据的目录(许多不同大小的子目录和文件)。移动始终在同一分区/驱动器内完成,因此无需实际移动磁盘上的所有文件。

不应该有任何文件锁定到要移动的dir的内容,但是,仍然经常,renameTo()无法完成其工作并返回false。(我只是猜测也许有些文件锁在Windows上会随意过期。

目前,我有一个使用复制和删除的回退方法,但这很糟糕,因为它可能需要很多时间,具体取决于文件夹的大小。我还考虑简单地记录这样一个事实,即用户可以手动移动文件夹,以避免等待数小时。但正确的方式显然是自动和快速的。

所以我的问题是,你是否知道一种替代的,可靠的方法,可以在Windows上使用Java进行快速移动/重命名,无论是使用普通的JDK还是一些外部库。或者,如果您知道一种简单的方法来检测和释放给定文件夹及其所有内容(可能是数千个单独的文件)的任何文件锁定,那也很好。


编辑:在这种特殊情况下,似乎我们只是通过考虑更多的事情而逃脱了使用;看到这个答案renameTo()


答案 1

另请参阅 JDK 7 中的 Files.move() 方法。

例如:

String fileName = "MyFile.txt";

try {
    Files.move(new File(fileName).toPath(), new File(fileName).toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
} catch (IOException ex) {
    Logger.getLogger(SomeClass.class.getName()).log(Level.SEVERE, null, ex);
}

答案 2

就其价值而言,还有一些进一步的概念:

  1. 在 Windows 上,如果目标目录存在,即使它为空,似乎也会失败。这让我感到惊讶,就像我在Linux上尝试过的那样,如果目标存在,只要它是空的,它就会成功。renameTo()renameTo()

    (显然,我不应该假设这种事情在各个平台上的工作方式是一样的;这正是Javadoc所警告的。

  2. 如果您怀疑可能存在一些滞留的文件锁定,请在移动/重命名之前稍等片刻可能会有所帮助。(在我们的安装程序/升级程序中的某个点中,我们添加了一个“睡眠”操作和一个不确定的进度条,持续约10秒,因为可能有一个服务挂在某些文件上)。甚至可以执行一个简单的重试机制,尝试 ,然后等待一段时间(可能会逐渐增加),直到操作成功或达到某个超时。renameTo()

在我的情况下,大多数问题似乎已经通过考虑上述两个因素来解决,因此我们毕竟不需要执行本机内核调用或类似的事情。