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

问题描述 投票:9回答:2

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

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

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

c# .net io
2个回答
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

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


Update: With .NET's Reference Source available, the implementation of Directory.Delete can be inspected. The first action of this method is to iterate over all files and delete them. The iteration is implemented using FindFirstFile/FindNextFile. The returned handle is stored as a SafeFindHandle, a concrete subclass of SafeHandle. As the documentation points out, the native handle is freed through a concrete ReleaseHandle override. ReleaseHandle is called from a (postponed) critical finalizer. Since finalization is non-deterministic, this explains the open handle, responsible for the delayed directory delete.

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


Other answers to this question did not identify the core issue, and work by coincidence at best. BanksySan's answer adds unrelated code that introduces a delay to allow time for open handles to be closed. Byeni's answer is closer, yet still off: When he talks about the object referencing the directory he almost nails it. However, the object referencing the directory is called a handle, a native resource. Native resources are disposed of in finalizers, and GC.Collect() does not run finalizers. This, too, appears to work by buying extra time.

5
投票

请改用DirectoryInfo,然后调用Refresh()

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

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

© www.soinside.com 2019 - 2024. All rights reserved.