为啥有时 Directory.CreateDirectory 会失败?

Posted

技术标签:

【中文标题】为啥有时 Directory.CreateDirectory 会失败?【英文标题】:Why sometimes Directory.CreateDirectory Fails?为什么有时 Directory.CreateDirectory 会失败? 【发布时间】:2016-05-06 06:58:14 【问题描述】:

这是我用来提取 zip 文件的代码,以确保目标目录中没有任何脏文件

internal void UnzipProject()

    if (Directory.Exists(SourceDir))
        Directory.Delete(SourceDir, true);

    if (File.Exists(CodeZipFile))
    
        Directory.CreateDirectory(SourceDir); // fails here
        ZipFile.ExtractToDirectory(CodeZipFile, SourceDir);
    

有时Directory.CreateDirectory(SourceDir) 无法创建新目录,我在下一行出现异常,但如果我退后一步重试创建目录,它可以工作。下一次执行时会重复完全相同的模式。

编辑 这是实际上关于 dir 没有创建的异常,我可以看到 src dir 不存在:

System.UnauthorizedAccessException was unhandled
  HResult=-2147024891
  Message=Access to the path '(...MyPath...)\src\MySolution.sln' is denied.
  Source=mscorlib
  StackTrace:
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
       at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
       at System.IO.Compression.ZipFileExtensions.ExtractToFile(ZipArchiveEntry source, String destinationFileName, Boolean overwrite)
       at System.IO.Compression.ZipFileExtensions.ExtractToDirectory(ZipArchive source, String destinationDirectoryName)
       at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName, Encoding entryNameEncoding)
       at System.IO.Compression.ZipFile.ExtractToDirectory(String sourceArchiveFileName, String destinationDirectoryName)
........

【问题讨论】:

你得到"sometimes"的例外是什么 你多久运行一次这个方法?每小时一次,每分钟一次,每秒1000次? 仅在应用程序启动时运行此方法。在生产中,它可能会在几分钟内被召回一次 有趣的是,人们对这个问题投了反对票?可以分享一下原因吗? 1) 是否有任何防病毒软件正在运行?您可以禁用它并重试吗? 2)这是发生在网络共享还是常规本地文件夹上? 3) 请您尝试使用 AlphaFS(替换所有 IO 命名空间同时修复大量错误(如长路径等)的库)。 【参考方案1】:

在 Windows 7、.Net 4.0、VS2010 下遇到此问题。看起来 Directory.Delete() 不是同步的,所以问题在于时间。我猜 Directory.CreateDirectory() 不会失败,因为现有文件夹被标记为删除。然后在 Directory.Delete() 完成时删除新文件夹。

我发现这始终有效:

if (Directory.Exists(myPath))
  
  Directory.Delete(myPath, true);
  while (Directory.Exists(myPath))
    System.Threading.Thread.Sleep(10);
  

Directory.CreateDirectory(myPath);

【讨论】:

这个方法是异步的,太疯狂了!感谢您的意见帮助我解决了这个问题。 一次又一次我不敢相信,但是是的,这是异步的。疯狂的。从这里确认 嗯,是的,Win32 RemoveDirectory API 上的文档说 The RemoveDirectory function marks a directory for deletion on close. Therefore, the directory is not removed until the last handle to the directory is closed.,所以如果有任何东西保持该目录的句柄处于打开状态,它还不会被删除。 感谢@Tom Lint。很高兴知道我猜对了。【参考方案2】:

错误实际上已经在异常中了。

System.UnauthorizedAccessException was unhandled

您需要添加代码来检查/验证用户是否有权访问该文件夹。

【讨论】:

不应该是访问问题,因为它可以重试。另外,出现异常时src dir根本不存在,如何检查访问权限? 您的重试逻辑与它没有任何关系。访问@Batuta 意味着权限 很抱歉造成混淆。通过说“重试”,我的意思是在同一个应用程序运行中退回调试器并再次重新执行这行代码。 你真的需要结合 Batuta 和 Twilight 的答案。您需要在 try-catch 块中调用 Directory.Delete()。如果异常是UnauthorizedAccessException,您的程序应该显示错误并停止。但是您还需要考虑长时间运行的删除。您正在删除一个文件夹,这意味着必须先删除其中的所有文件,然后才能删除该文件夹。【参考方案3】:

感谢大家帮我解决这个问题。问题是在调用它的删除后创建一个目录。在我的情况下,删除的目录是空的,但可能是由于文件系统延迟,在完全删除之前它变得无法访问。我正在分享解决方案,以供其他面临相同问题的人使用:

internal void UnzipProject()

    if (Directory.Exists(SourceDir))
    
        DirectoryInfo di = new DirectoryInfo(SourceDir);

        foreach (FileInfo file in di.GetFiles())
            file.Delete();

        foreach (DirectoryInfo dir in di.GetDirectories())
            dir.Delete(true);
    

    if (File.Exists(zipFile))
        ZipFile.ExtractToDirectory(zipFile, SourceDir);

    else
    
        if (Directory.Exists(SourceDir))
            Directory.Delete(SourceDir, true);
    

【讨论】:

【参考方案4】:

我自己也经历过这种行为。如果我没记错的话,这是因为 Directory.Delete 仍在尝试删除目录,同时 Directory.CreateDirectory 正在尝试重新创建它。 CreateDirectory 将失败,因为系统仍锁定该资源以供删除。

我通过在调用 Delete 和调用 CreateDirectory 之间引入一点延迟来避免这个问题。我记得使用过的另一个选项是重命名目录,然后将其删除。例如,如果原始目录名为 MyApp,我会将其重命名为 DeleteMe,然后删除该目录。 CreateDirectory 应该能够创建 MyApp 目录,因为它不再存在。

【讨论】:

【参考方案5】:

我的同事在频繁重写文件时遇到此错误。他告诉 Fyle 系统很慢。如果你有同样的问题,你尝试创建一个尚未删除的文件夹。

尝试在 UnauthorizedAccessException 上重复一次您的方法,或\并在 Directory.Delete 之后添加 Thread.Sleep(100)。

【讨论】:

就我而言,目录从未存在过,因此不会被删除。

以上是关于为啥有时 Directory.CreateDirectory 会失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 == 比较两个整数有时有效,有时无效? [复制]

pip:为啥有时安装为鸡蛋,有时安装为文件

为啥有时我的页面中的 UI 有时会出现有时不出现?

python nonlocal - 为啥有时需要它,有时不需要它

为啥打印 unsigned char 有时有效,有时无效?在 C 中

为啥Android有时无法获取位置