java - 递归移动目录并在Java中合并它们的有效方法

标签 java performance java-8 hard-drive

我正在寻找在 Java 中递归移动目录的最有效方法。目前,我正在使用 Apache commons-io,如下面的代码所示。 (如果 destDir 存在并包含部分文件,我希望覆盖这些文件并合并嵌套目录结构)。

FileUtils.copyDirectoryToDirectory(srcDir, destDir);
FileUtils.deleteDirectory(srcDir);

虽然这可以解决问题,但在我看来,它的效率不够高。至少有两个问题浮现在脑海中:

  • 您将需要两倍的空间。
  • 如果这是 SSD,将数据复制到驱动器的另一部分,然后删除旧数据最终会对硬件产生影响,因为这实际上会缩短硬盘的使用生命周期。

执行此操作的最佳方法是什么?

根据我的理解,commons-io 似乎没有使用 Files 中可用的新 Java 7/8 功能。另一方面,如果 destDir 存在,我无法让 Files.move(...) 工作(“让它工作”我的意思是它合并目录结构——它提示 destDir 存在)。

关于移动失败(如有错误请指正):

  • 据我所知,原子移动只有在一次移动所有文件时才会成功。如果我没有理解错的话,这意味着这是先复制再删除。我不认为这就是我要找的。
  • 如果无法移动某个路径/文件,则操作应停止并抛出异常,保留它到达的当前源路径。

请注意,我并不局限于使用 commons-io 库。我愿意接受建议。我正在使用 Java 8。

最佳答案

这只是对问题中“需要对文件系统发生什么”部分的回答,不是如何使用 Java 来完成。

即使您确实想调用外部工具,Unix mv 也不像 Windows 资源管理器。同名目录不合并。所以你需要自己实现,或者找到一个库函数。没有一个 Unix 系统调用可以完成整个递归操作(更不用说原子操作了),所以这是您的代码或库函数必须做的事情。

如果您需要从一个版本的树自动切换到另一个版本,则需要构建一棵新树。这些文件可以硬链接(hard link)到旧版本。即做相当于

cp -al dir/  new
rsync -a /path/to/some/stuff/  new/
# or maybe something smarter / custom that renames instead of copies files.

# your sanity check here

mv  dir old &&
mv  new dir &&   # see below for how to make this properly atomic
rm -rf old

这会留下一个窗口,其中 dir 不存在。要解决这个问题,请添加 level of indirection, by making dir a symlink .符号链接(symbolic link)可以是 replaced atomically with mv (but not ln -sf) .所以在 Java 中,你想要的东西最终会执行 rename 系统调用,而不是 unlink/rename


除非您有大量极小的文件(小于 100 字节),否则构建硬链接(hard link)场的目录元数据操作比目录树的完整副本便宜得多。文件数据将保留(甚至永远不会被读取),目录数据将是一个新副本。将为所有文件写入文件元数据(inode)(以更新 ctime 和链接计数,在创建硬链接(hard link)场时,以及在删除旧树时再次更新,使文件保留原始链接计数。


如果您在最新的 Linux 内核上运行,则有一个 new(2013) system call (称为 renameat2 )可用,可以原子地交换两条路径。这避免了符号链接(symbolic link)级别的间接访问。不过,使用来自 Java 的仅限 Linux 的系统调用会比它的值(value)更麻烦,因为符号链接(symbolic link)很容易。

关于java - 递归移动目录并在Java中合并它们的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32025094/

相关文章:

Java 8 lambda 从对象列表创建字符串列表

java - 将一个 CharArrayBuffer 复制到另一个 CharArrayBuffer

java - 底部的 android 菜单

Javascript在数组中添加相同的元素N次

java - 渲染各种类型的单元时回收器 View 中的性能问题

java - 尝试理解 Java 8 中的 lambda 和流

java - 如何更改旧单元测试的私有(private)抽象父字段

java 调试 - 观察超出范围的变量

Java:对于这种情况我应该使用什么集合类型?

java - 在java中将逗号分隔的字符串转换为json