如何在Java中以原子方式替换另一个目录?

时间:2010-12-08 16:50:15

标签: java file atomic directory

我有一个目录,其中包含提供给客户的数据文件,例如/srv/data。在进行一系列更新时,我正在处理/srv/data_tmp,并且在操作结束时,我希望用data原子地替换data_tmp。当目标是现有目录时,File.renameTo()总是为我返回false。我怎么能这样做?

4 个答案:

答案 0 :(得分:1)

您可以使用符号链接(或junction in Windows XP)替换/srv/data目录,并在适当时更改链接的目标。 但是,您无法使用Java 6 API执行此操作 - 您必须依赖库或自行编写命令行命令。

注意:我不保证该操作的原子性。

答案 1 :(得分:1)

Linux rename系统调用不允许这样做(rename系统调用只能覆盖一个空目录),所以我怀疑在Linux上用Java做这件事。

答案 2 :(得分:1)

恐怕你做不到。至少不在SO级别。因此,即使您在Java应用程序的上下文中管理“原子性”,也无法保证其他一些“流氓”进程会干扰实际的文件系统级别。

如果我是你,我会阅读this article(相当陈旧,但应该给你一些想法),然后看看你是否可以将建议的方法移植到more modern version

哦,等等,有人已经this了!

显然你不是the first one to ask here,也不是

祝您好运......

答案 3 :(得分:0)

使用"符号链接"的组合完全可以实现这一目标。和"重命名",以及一个中间的tmp目录。以下示例在shell中,但您可以轻松地在此处转换功能以使用基础调用:

mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./

此处的示例来自:http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/

这归结为(伪代码):

mkdir('./tmp');
mkdir('./tmp/real_dir1');
mkdir('./tmp/real_dir2');
symlink('./tmp/real_dir1', './target_dir')
symlink('./tmp/real_dir2', './tmp/target_dir')
rename('./tmp/target_dir', './target_dir')

此处的最终重命名是原子的,因此操作将成功或完全失败,从使用该目录的任何进程来看,该操作都是原子的。