在Directory.Delete Directory.Exists有时返回true?

时间:2014-06-17 13:43:30

标签: c# .net io

我有非常奇怪的行为。我有,

Directory.Delete(tempFolder, true);
if (Directory.Exists(tempFolder))
{
}

有时Directory.Exists返回true。为什么?可能是探险家开放了?

2 个答案:

答案 0 :(得分:17)

Directory.Delete调用Windows API函数RemoveDirectory。观察到的行为记录在案:

  

RemoveDirectory函数标记要在关闭时删除的目录。因此,在关闭目录的最后一个句柄之前,不会删除该目录。

遗憾的是,.NET文档遗漏了这些信息。是否记录了静态Directory.Delete方法是否打开了目录句柄。同样,如果确实如此,则在句柄关闭时不会记录。

如果没有这些信息,您可以做的最好是轮询完成:

Directory.Delete(tempFolder, true);
while (Directory.Exists(tempFolder)) Thread.Sleep(0);
// At this point the directory has been removed from the filesystem

尽管通常应该首先避免轮询而不是事件,但是安装文件系统观察器会有点过头了。但请记住,此操作不是免费的,特别是在处理网络驱动器时。


更新:在.NET Reference Source可用的情况下,可以检查Directory.Delete的实施情况。此方法的第一个操作是迭代所有文件并删除它们。迭代使用FindFirstFile / FindNextFile实现。返回的句柄存储为SafeFindHandleSafeHandle的具体子类。正如documentation指出的那样,本机句柄通过具体的ReleaseHandle覆盖释放。从一个(推迟的)关键终结器调用ReleaseHandle。由于最终确定是非确定性的,这解释了打开句柄,负责延迟目录删除。

然而,这些信息无助于找到比上述更好的解决方案(轮询完成)。


此问题的其他答案并未确定核心问题,并且最多只能使用巧合BanksySan's answer添加了不相关的代码,这些代码引入了延迟以允许关闭打开句柄的时间。 Byeni's answer离得更近了,但仍然关闭:当他谈到引用目录的对象时,他几乎指出了它。但是,引用该目录的对象称为 handle ,即本机资源。本机资源在终结器中处理,GC.Collect()不运行终结器。这也似乎可以通过购买额外的时间来实现。

答案 1 :(得分:5)

改为使用DirectoryInfo,并在其上调用Refresh()

        var dir = new DirectoryInfo(tempFolder);
        dir.Delete();
        dir.Refresh();

因为我们在目录上执行了许多操作,所以使用DirectoryInfo而不是Directory会更高效。这可能解释了为什么静态类上没有Refresh(),它意味着一次性操作,因此永远不需要刷新。