使用Directory.Delete()和Directory.CreateDirectory()覆盖文件夹

在我的WebApi操作方法中,我想使用以下代码创建/覆盖文件夹:

 string myDir = "..."; if(Directory.Exists(myDir)) { Directory.Delete(myDir, true); } Directory.CreateDirectory(myDir); // 1 - Check the dir Debug.WriteLine("Double check if the Dir is created: " + Directory.Exists(myDir)); // Some other stuff here... // 2 - Check the dir again Debug.WriteLine("Check again if the Dir still exists: " + Directory.Exists(myDir)); 

问题

奇怪的是,有时在创建目录后,该目录不存在!

有时第一次检查目录时(数字1是); Directory.Exist()返回true ,其他时间返回false 。 第二次检查目录时(数字2的位置)也是如此。

笔记

  • 这部分代码都没有抛出任何exception。
  • 只有在服务器上发布网站时才能重现这一点。 (Windows server 2008)
  • 访问同一文件夹时发生。

问题

  • 这是并发问题竞争条件吗?
  • WebApi或操作系统不处理并发吗?
  • 这是覆盖文件夹的正确方法吗?
  • 当我们对同一个文件有很多API请求时,我是否应该手动锁定文件?

或者一般情况:

  • 这种奇怪行为的原因是什么?

更新:

  • 使用DirectoryInfoRefresh()而不是Directory不能解决问题。

  • 仅当Delete递归选项为true时才会发生。 (并且目录不为空)。

许多文件系统操作在某些文件系统上是不同步的(在Windows的情况下 – NTFS)。 以RemoveDirectory调用为例(在某些时候由Directory.DeleteDirectory调用):

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

如您所见,它将不会真正删除目录,直到它的所有句柄都关闭,但Directory.DeleteDirectory将完成。 在您的情况下,这也很可能是这样的并发问题 – 在您执行Directory.Exists时,并未真正创建目录。

因此,只需定期检查您需要什么,不要认为.NET中的文件系统调用是同步的。 在某些情况下,您还可以使用FileSystemWatcher来避免轮询。

编辑:我在想如何重现它,这是代码:

 internal class Program { private static void Main(string[] args) { const string path = "G:\\test_dir"; while (true) { if (Directory.Exists(path)) Directory.Delete(path); Directory.CreateDirectory(path); if (!Directory.Exists(path)) throw new Exception("Confirmed"); } } } 

您会看到,如果所有文件系统调用都是同步的(在.NET中),则此代码应该没有问题地运行。 现在,在运行该代码之前,在指定路径创建空目录(最好不要使用SSD)并使用Windows资源管理器打开它。 现在运行代码。 对我来说,它会抛出Confirmed(它完全重现你的问题)或抛出Directory.Delete说该目录不存在(几乎相同的情况)。 它100%的时间对我来说。

这是另一个代码,当我在我的机器上运行时,确认File.Exists肯定可以在File.Delete调用之后直接返回true:

 internal class Program { private static void Main(string[] args) { while (true) { const string path = @"G:\test_dir\test.txt"; if (File.Exists(path)) File.Delete(path); if (File.Exists(path)) throw new Exception("Confirmed"); File.Create(path).Dispose(); } } } 

例外

为此,我打开了G:\ test_dir文件夹,在执行此代码时尝试打开不断出现和消失的test.txt文件。 经过几次尝试,抛出了确认exception(虽然我没有创建或删除该文件,并且在抛出exception后,它已经不存在于文件系统中)。 因此,在多种情况下可能存在竞争条件,我的答案是正确的。

对我来说听起来像是竞争条件。 不知道为什么 – 你没有提供足够的细节 – 但你可以做的是将所有内容包装在lock()语句中,看看问题是否已经消失。 当然,这不是生产就绪的解决方案,它只是一种快速检查方式。 如果它确实是竞争条件 – 您需要重新考虑重写文件夹的方法。 可以创建“GUID”文件夹,完成后 – 使用最新的GUID更新DB以指向最新的文件夹?