为什么Guava中的Files.deleteDirectoryContents()被弃用?

10
在Guava 10+版本中,谷歌已经废弃了Files.deleteDirectoryContents()。JavaDoc说:

过时的。该方法存在符号链接检测不良和竞态条件。只有通过外壳调用操作系统命令(如rm -rf或del/s),才能适当地支持此功能。这个方法计划在Guava 11.0版本中从Guava中删除。

我困惑的是为什么会有竞态条件。我认为这个方法实际上很有用,而且认为通过外壳调用操作系统是一个不好的解决方案。作者可以分享一下为什么做出这个决定吗?


更明确地说,我认为拥有竞态条件问题并不是一个重大的错误。许多库,如ArrayList,都不是线程安全的或具有竞态条件。甚至File.remove也有同样的问题。但是它们都有文档记录。所以除了文档已经提到的内容,我希望听到一个解释他们为什么选择将其弃用的答案。 - Amir Raminfar
1
这种竞态条件与典型的非线程安全类之间的区别在于它没有“修复”方法。相比之下,您可以通过在锁对象上同步来解决非线程安全类的Java线程安全问题。一个不能按人们期望执行其功能的方法是不好的方法。 - Stephen C
“没有修复”是指在Guava或Java平台级别上无法进行任何修复。从理论上讲,在操作系统级别上可能会修复这个问题;例如,如果文件系统被制作为ACID事务性的。但不要指望等待太久…… - Stephen C
4个回答

5
我不理解为什么会出现竞态条件。
举个例子,假设一个线程调用Files.deleteDirectoryContents()方法,并且同时有第二个线程(或外部进程)在该目录中创建了一个新文件。当您从调用中返回时,您能够确认该目录为空吗?答案是否定的!
总之,如果你发现这个方法的功能对你很有用……尽管它存在缺陷……你可以自由地复制代码,进行修改,并将其嵌入到你的应用程序中。(只需检查Guava源代码许可证并确保符合即可。)
作者能否分享一下他们为何做出这个决定?
我认为他们已经分享过了,可以查看弃用通知。如果你需要更多信息,可以尝试搜索问题跟踪器和Guava讨论组。你甚至可以在讨论组上礼貌地询问,虽然如果你的目的是改变他们的想法,我觉得你可能会失败。

4
对于向操作系统提供支出,同样适用,不是吗? - anders
+1 如果使用操作系统外壳,情况不也是一样的吗?我认为,如果一个库不支持多线程,那么应该在文档中进行说明,并由开发人员确保正确使用它。 - Amir Raminfar
@Stephen C,我并不想改变任何人的想法。我相信这个被弃用的方法一定有其合理的原因。我只是认为除了竞态条件之外,可能还存在其他问题导致需要这样做。但是很多库都存在竞态条件,所以我认为可能会有更好的原因。 - Amir Raminfar
Guava非常注重使意外出错的事情变得尽可能困难...例如竞态条件。 - Louis Wasserman
1
@AmirRaminfar - 作者还将“符号链接检测不佳”列为弃用的原因之一。我认为他们指的是在纯Java中可靠/可移植/廉价地区分文件和指向文件的符号链接是困难的。而你必须为此方法做出判断。这些都是非常好的理由。在我看来,没有更好的理由了。 - Stephen C
显示剩余3条评论

5
竞争条件的风险可能比“目录可能不为空”更大,这在一定程度上是由于符号链接检测不佳。请考虑以下代码片段:
// Symbolic links will have different canonical and absolute paths
if (!directory.getCanonicalPath().equals(directory.getAbsolutePath())) {
  return;
}
... delete its contents ...

如果在检查期间directory是一个普通目录,但之后是指向/的符号链接,则deleteDirectoryContents将愉快地尝试清除整个文件系统。
也许有一些解决方法,但我们还没有找到。为潜在的安全漏洞制定临时修复措施是令人不安的。

1

你是认真的吗?你正试图解决多线程操作:

例如,假设一个线程调用Files.deleteDirectoryContents(),而另一个线程(或外部进程)同时在目录中创建一个新文件。当您从调用返回时,您可以依靠目录为空吗?不行!

那么另一个进程操作该目录呢?这无法解决,您不应处理事务,因为根本不可能。有人会制作指向根目录的符号链接,以便我删除整个文件系统-访问权限对文件系统处理程序有所帮助吗?如果您以root身份运行此类操作,则应了解自己在做什么。禁用文件系统中的删除文件怎么样,这很危险!如果Guava作者解决了这些愚蠢的问题,我将使用不同的库。


1

有关损坏的符号链接检测的更多示例,请参见用户提交的这些错误

简而言之,除非您提供该目录的规范路径,否则无法清除目录。 如果/tmp是指向/some/other/directory的链接,则deleteDirectoryContents无法清除/tmp/mytempdirectory。 也许在这里还有可能的解决方法,但我们束手无策。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接