尝试以编程方式删除文件夹时出现“目录不为空”错误

Posted

技术标签:

【中文标题】尝试以编程方式删除文件夹时出现“目录不为空”错误【英文标题】:"Directory is not empty" error when trying to programmatically delete a folder 【发布时间】:2012-09-07 01:30:43 【问题描述】:

在我的应用程序中,我构建了一个系统,用户可以在其中创建图片库。照片以 category_name/gallery_name/pictures 格式保存在磁盘上的文件夹中。每张上传的照片都存储在上面给出的相关目录结构下。

当尝试删除类别以及从数据库中删除时,我也想从系统中删除相关文件夹。当我第一次收到错误消息“目录不为空”时,我searched and found这个解决方案:

public static void DeleteDirectory(string target_dir)
    
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        

        foreach (string dir in dirs)
        
            DeleteDirectory(dir);
        

        Directory.Delete(target_dir, false);
    

使用此解决方案,“gallery_name”文件夹中的照片会被很好地删除,然后gallery_name 文件夹本身也会被删除。所以我们现在只剩下一个空的category_name 文件夹。然后调用上述子例程中的最后一段代码 (Directory.Delete(target_dir, false);) 以删除 category_name 文件夹。错误再次引发..

有人知道解决办法吗?

    Directory.Delete(target_dir, true); 不起作用,这就是我尝试替代方案的原因。 我可以完全控制父文件夹,并且 category_name 和 gallery_name 文件夹也是以编程方式创建的,没有任何问题。 正如我所提到的,使用此代码删除子目录(gallery_name 文件夹)及其内容(照片)就好了。导致错误的是 category_name 文件夹,即使在这段代码之后,它只是一个空文件夹。

我得到的异常信息是:

System.IO.IOException was unhandled by user code
  HResult=-2147024751
  Message=The directory is not empty.

  Source=mscorlib
  StackTrace:
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive, Boolean throwOnTopLevelDirectoryNotFound)
       at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive, Boolean checkHost)
       at System.IO.Directory.Delete(String path)
       at MyApp.PhotoGallery.Categories.deleteCategory(Int32 cID, String categoryname) in d:\Documents\My Dropbox\web projects\MyAppFolder\App_Code\BLL\PhotoGallery.vb:line 291
       at _admhades_PhotoGallery.deleteCategory(Int32 categoryID, String categoryname) in d:\Documents\My Dropbox\web projects\HavadisPre\_admhades\PhotoGallery.aspx.vb:line 71

【问题讨论】:

你的文件夹权限是什么? 我拥有完全控制权.. 作为旁注,文件夹也是以编程方式创建的.. 我猜您是从***.com/questions/329355/… 获得的以上信息 - 您确定该文件夹未在 Windows 资源管理器中打开,例如其他答案?其他东西还能锁定文件夹吗? 我建议Sleep(..) 执行线程一秒钟。在您调用最后一条指令的那一刻,可能是 Windows 尚未从中删除文件... @Tigran Peppering 使用 Sleep 的代码使其工作相当于将您的电视拍到一边使其再次工作。 【参考方案1】:

您可以使用Directory.Delete(target_dir, true); 递归删除目录和所有文件。您不必编写自定义函数。

【讨论】:

你在使用的时候遇到了什么异常?它是 .NET 框架方法,除非您遇到权限问题,否则它应该可以工作。 也来自文档:'在某些情况下,如果您在文件资源管理器中打开了指定的目录,Delete 方法可能无法删除它。' 好的,我只用 Directory.Delete(target_dir, true) 再试了一次,我确认错误消息完全一样.. 另外,尝试了 thread.sleep 两秒钟,还是一样错误..这让我发疯! 对这个问题有希望吗?我还在苦苦挣扎 问题明确表示,这不起作用。 (众所周知,如果目录包含只读文件,则它不起作用。抛出异常的事实很好,但无助于实际删除文件夹。)如果人们会使用此功能,似乎我认为该软件大部分都可以工作,但有时不能。【参考方案2】:

这对我有用,即使我打开了文件资源管理器:

public static void DeleteFilesAndFoldersRecursively(string target_dir)

    foreach (string file in Directory.GetFiles(target_dir))
    
        File.Delete(file);
    

    foreach (string subDir in Directory.GetDirectories(target_dir))
    
        DeleteFilesAndFoldersRecursively(subDir);
    

    Thread.Sleep(1); // This makes the difference between whether it works or not. Sleep(0) is not enough.
    Directory.Delete(target_dir);

【讨论】:

【参考方案3】:

这个问题把我逼疯了。使用Directory.Delete(dirPath, recursive: true); 删除目录及其内容时,我看到了海报的确切行为。就像海报一样,即使调用引发了“目录不为空”的异常。该调用实际上递归地删除了目录的所有内容,但未能删除所提供路径的根目录。疯狂。

在我的情况下,我发现问题是由 窗口资源管理器中的左侧导航树 是否显示我试图删除的目录打开所致。如果是这样,那么似乎正在发生某种排队删除或目录内容删除的缓存导致问题。此行为可能看起来很奇怪且不可预测,因为在 Windows 资源管理器中查看要删除的目录不会导致此问题只要该目录未在 Windows 左侧导航树中打开

可能需要几张图片来说明这一点。请注意,在下面的路径中,窗口显示 1346。1346 是目录 1001 的子目录。在这种情况下,递归删除 1346 的调用将成功,因为我们在 Window 的资源管理器中查看 1346 本身不是问题。

但在下图中,请注意,在下面的路径中,我们正在查看目录 1018。但是在左侧中殿,我们打开了目录 1349(见箭头)。这就是导致问题的原因,至少对我而言。如果在这种情况下,我们为目录 1349 的dirPath 调用Directory.Delete(dirPath, recursive: true);,它将抛出“目录不为空”。例外。但是如果我们在异常发生后检查目录,我们会发现它已经删除了目录的所有内容,实际上它现在是空的。

所以这看起来很像一个边缘情况,但它是我们开发人员可能遇到的情况,因为当我们测试代码时,我们希望观察文件夹是否被删除。并且很难理解是什么触发了它,因为它是关于 Windows 资源管理器的左侧导航栏而不是窗口的主要内容区域。

无论如何,尽管我不喜欢下面的代码,但它确实在所有情况下都为我解决了问题:

        //delete the directory and it's contents if the directory exists
        if (Directory.Exists(dirPath)) 
            try 
                Directory.Delete(dirPath, recursive: true);                //throws if directory doesn't exist.
             catch 
                //HACK because the recursive delete will throw with an "Directory is not empty." 
                //exception after it deletes all the contents of the diretory if the directory
                //is open in the left nav of Windows's explorer tree.  This appears to be a caching
                //or queuing latency issue.  Waiting 2 secs for the recursive delete of the directory's
                //contents to take effect solved the issue for me.  Hate it I do, but it was the only
                //way I found to work around the issue.
                Thread.Sleep(2000);     //wait 2 seconds
                Directory.Delete(dirPath, recursive: true);
            
        

我希望这对其他人有所帮助。追查和解释花了相当多的时间,因为这真的很奇怪。

【讨论】:

如果错误在 catch 块内再次被追溯怎么办?我们是否应该根据需要多次运行您显示的代码,直到错误停止发生?还是它总是在 catch 块内的第二次尝试中起作用?或者,我们是否应该在放弃删除文件夹之前尝试几次? 如果它在这里抛出了 catch 块,那么可能有一个不能删除目录的正当原因(例如,包含打开的文件,包含您无权删除的文件等) 这对我有用。但是我不需要等待2000毫秒,只需要1:Thread.Sleep(1)【参考方案4】:

这并不像我想要的那样完整,但这些是我过去遇到类似问题时帮助过我的事情。

该文件正在被其他东西使用。这意味着您已经创建了一个文件夹/文件,但尚未发布它。使用 .Close()(如果适用)。

与锁相关的问题。

当指定的根文件夹中没有文件夹时,您使用了Directory.Delete(rootFolder, true)(其中 true 表示递归删除)。

它被另一个程序打开。现在,除了安装Process Monitor 之外,我不知道从哪里开始,这可能会有所帮助,但这只在某些情况下才真正有效。

过去,Anti Virus 之类的东西,甚至(在 Windows 上)Defender 之类的东西都导致了这个问题。

当您调用 Directory.Delete 并以这种方式打开文件时, Directory.Delete 成功删除所有文件,但是当 Directory.Delete 调用 RemoveDirectory 一个“目录不为空” 抛出异常,因为有一个标记为删除的文件,但是 实际上并未删除。

显而易见的事情包括确保您有权删除文件夹(不仅是您,还包括运行程序的帐户)。

您尝试删除的文件是只读的。首先将文件夹中所有文件的文件属性由只读更改。

该路径由其他 Windows 组件共享,因此在创建/删除文件夹时要小心。

SourceSource

【讨论】:

哇!感谢您提供所有这些信息。我从未尝试过解决这个问题的唯一一件事(是的,它仍然没有解决!)是使用 .Close 我会试一试,让你知道。我真的很感激你的帖子和帮助别人的意图。谢谢.. ***.com/a/12544296/206730 "这可能是因为 Windows 资源管理器中的某种延迟/缓存。" @Kiquenet 最后,我浏览了每个文件和文件夹,并将其从只读更改。然后我等了 N 时间(以防 AV 扫描)。然后我尝试删除,失败时,我重命名了文件/文件夹,然后再次尝试。这是 100% 成功的,虽然看起来有些东西只是删除并且几乎不需要使用重命名,但 MSDN 确实解释了这是一个选项(虽然我现在找不到页面)! 无,我不再有访问权限 - 真的很抱歉......但这很容易。从字面上看,将所有文件作为字符串数组获取,然后通过每次移动更改属性进行迭代。然后,等待 N 秒并尝试删除。在异常情况下,等待,重命名现有文件夹(在我的情况下,错误是文件夹是只读的)......【参考方案5】:

在我的例子中,我创建了我的目录,我的程序以管理员身份运行。当我尝试在没有管理员权限的情况下删除同一目录时,出现“目录不为空”错误。

解决方案:以管理员身份运行应用程序或手动删除。

【讨论】:

以上是关于尝试以编程方式删除文件夹时出现“目录不为空”错误的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式(但不是以声明方式)实例化小部件时出现 Dojo 重复 ID 错误

Microsoft 文档在以编程方式生成 SAS 令牌时出现问题。错误:“签名字段格式不正确”

尝试访问以编程方式创建的 <iframe> 的文档对象时出现“访问被拒绝”JavaScript 错误(仅限 IE)

在删除文件时出现0x80070091,我用知道里面的方法删会出现chkdsk啥啥的

以编程方式设置动态uiimageview时出现LayoutConstraint错误

从 /system/app 以编程方式安装具有 INSTALL_PACKAGES 权限的应用程序时出现问题