问题
Java的File.renameTo()有问题,特别是在Windows上,似乎。作为API documentationsays,
此方法行为的许多方面本质上依赖于平台:重命名操作可能无法将文件从一个文件系统移动到另一个文件系统,它可能不是原子的,如果具有目标摘要的文件可能不会成功pathname已存在。应始终检查返回值以确保重命名操作成功。
就我而言,作为升级过程的一部分,我需要移动(重命名)一个可能包含千兆字节数据的目录(许多子目录和不同大小的文件)。移动总是在同一个分区/驱动器内完成,因此不需要物理移动磁盘上的所有文件。
不应该将任何文件锁定到要移动的目录的内容,但是,通常,renameTo()仍然无法完成其工作并返回false。 (我只是猜测某些文件锁可能会在Windows上随意过期。)
目前我有一个使用复制和删除的后备方法,但这很糟糕,因为它可能需要很多时间,具体取决于文件夹的大小。我还在考虑简单地记录用户可以手动移动文件夹以避免等待数小时的事实。但正确的方式显然是自动而快速的。
所以我的问题是,你知道一种替代的,可靠的方法,用Windows快速移动/重命名,使用普通的JDK或一些外部库。或者,如果你知道检测并释放给定文件夹及其所有内容(可能是数千个单独文件)的任何文件锁,那也没关系。
编辑:在这个特殊情况下,我们似乎只是考虑到了一些事情而使用了renameTo(); seethis answer。
#1 热门回答(45 赞)
另请参见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 热门回答(25 赞)
对于它的价值,还有一些进一步的概念:
在Windows上,如果目标目录存在,renameTo()似乎失败,即使它是空的。这让我感到惊讶,就像我在Linux上尝试过的那样,只要目标存在,renameTo()就会成功,只要它是空的。 (显然我不应该假设这种事情在不同的平台上都是一样的;这正是Javadoc所警告的。)
如果你怀疑可能存在一些挥之不去的文件锁,请在移动/重命名之前稍等一下可能会有所帮助。 (在我们的安装程序/升级程序中,我们添加了一个"睡眠"操作和一个不确定的进度条大约10秒,因为某些文件可能会挂起一个服务)。也许甚至做一个简单的重试机制,尝试renameTo(),然后等待一段时间(可能会逐渐增加),直到操作成功或达到一些超时。
在我的情况下,大多数问题似乎已经通过考虑上述两个问题得到解决,所以我们不需要做本机内核调用,或者毕竟是一些这样的事情。
#3 热门回答(19 赞)
最初的帖子要求"在Windows上使用Java进行快速移动/重命名的替代,可靠的方法,使用普通的JDK或一些外部库。"
此处未提及的另一个选项是apache.commons.iolibrary的v1.3.2或更高版本,其中包括FileUtils.moveFile()。
它抛出一个IOException,而不是在出错时返回boolean false。