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

A-S*_*ani 10 c# asp.net-web-api asp.net-web-api2

在我的WebApiaction方法中,我想使用以下代码创建/覆盖一个文件夹:

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));
Run Code Online (Sandbox Code Playgroud)

问题

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

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

笔记

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

问题

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

或者一般情况:

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

更新:

  • 使用DirectoryInfoRefresh(),而不是Directory不解决问题.

  • 只有发生在当递归的选项删除true.(并且目录不为空).

Evk*_*Evk 10

许多文件系统操作在某些文件系统上不同步(在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");                 
        }            
    }        
}
Run Code Online (Sandbox Code Playgroud)

您会看到,如果所有文件系统调用都是同步的(在.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();
        }
    }        
 }
Run Code Online (Sandbox Code Playgroud)

例外

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