我正在使用 .NET 3.5,尝试使用以下方法递归删除目录:
Directory.Delete(myPath, true);
我的理解是,如果文件正在使用中或存在权限问题,这应该抛出,否则它应该删除目录及其所有内容。
但是,我偶尔会得到这个:
System.IO.IOException: The directory is not empty.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
...
我对该方法有时会抛出并不感到惊讶,但是当递归为真时,我很惊讶地收到此特定消息。(我知道目录不为空。
有没有理由我会看到这个而不是访问违规异常?
编者按:尽管此答案包含一些有用的信息,但实际上对 的运作是不正确的。请阅读此答案的评论以及此问题的其他答案。Directory.Delete
我以前遇到过这个问题。
问题的根源是此函数不会删除目录结构中的文件。因此,您需要做的是创建一个函数,该函数在删除目录本身之前删除目录结构中的所有文件,然后删除所有目录。我知道这违背了第二个参数,但这是一种更安全的方法。此外,您可能希望在删除文件之前立即从文件中删除只读访问属性。否则,这将引发异常。
只需将此代码放入您的项目中即可。
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);
}
另外,对我来说,我个人对允许删除的机器区域添加了限制,因为您希望有人调用此函数或.C:WINDOWS (%WinDir%)
C:
如果您尝试递归删除目录并且目录在资源管理器中打开,将被删除,但即使您去查看时它为空,您也会收到错误“目录不为空”。任何应用程序(包括资源管理器)的当前目录都保留该目录的句柄。当您调用 时,它会从下到上删除:,然后 。如果在资源管理器中打开,资源管理器将检测删除 ,向上更改目录并清理打开的句柄。由于文件系统以异步方式运行,因此操作会因与资源管理器冲突而失败。a
ab
b
a
Directory.Delete(true)
b
a
b
b
cd ..
Directory.Delete
我最初发布了以下解决方案,其想法是中断当前线程以允许资源管理器有时间释放目录句柄。
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
但这仅在打开的目录是您要删除的目录的直接子目录时才有效。如果在资源管理器中打开,并且您在 上使用它,则此技术将在删除和 .abcd
a
d
c
此方法将处理深层目录结构的删除,即使在资源管理器中打开了某个较低级别的目录也是如此。
/// <summary>
/// Depth-first recursive delete, with handling for descendant
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
foreach (string directory in Directory.GetDirectories(path))
{
DeleteDirectory(directory);
}
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Directory.Delete(path, true);
}
catch (UnauthorizedAccessException)
{
Directory.Delete(path, true);
}
}
尽管我们自己做了额外的递归工作,但我们仍然必须处理在此过程中可能发生的情况。目前尚不清楚第一次删除尝试是否为第二次成功尝试铺平了道路,或者是否仅仅是抛出/捕获异常引入的计时延迟,允许文件系统赶上。UnauthorizedAccessException
您可以通过在块的开头添加 a 来减少在典型条件下引发和捕获的异常数量。此外,在系统负载过重的情况下,您可能会通过两次尝试并失败。将此解决方案视为更可靠的递归删除的起点。Thread.Sleep(0)
try
Directory.Delete
此解决方案仅解决与 Windows 资源管理器交互的特殊性。如果您想要一个坚如磐石的删除操作,要记住的一件事是,任何内容(病毒扫描程序等)都可以随时打开您尝试删除的内容的句柄。所以你必须稍后再试。稍后删除对象以及尝试多少次取决于删除对象的重要性。正如 MSDN 所指出的,
可靠的文件迭代代码必须考虑到文件系统的许多复杂性
。
这个无辜的声明,只提供了NTFS参考文档的链接,应该让你的头发竖起来。
(编辑:很多。这个答案最初只有第一个不完整的解决方案。
在继续之前,请检查您控制的以下原因:
否则,请检查您无法控制的以下合法原因:
如果以上任何一种是问题所在,您应该在尝试改进删除代码之前了解为什么会发生这种情况。你的应用应该删除只读或无法访问的文件吗?谁这样标记它们,为什么?
一旦排除了上述原因,仍然存在虚假故障的可能性。如果有人持有要删除的任何文件或文件夹的句柄,则删除将失败,并且有人可能枚举文件夹或读取其文件的原因有很多:
处理虚假故障的一般方法是多次尝试,在尝试之间暂停。你显然不想永远尝试下去,所以你应该在一定次数的尝试后放弃,要么抛出异常,要么忽略错误。喜欢这个:
private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
const int magicDust = 10;
for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
try {
Directory.Delete(destinationDir, true);
} catch (DirectoryNotFoundException) {
return; // good!
} catch (IOException) { // System.IO.IOException: The directory is not empty
System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);
// see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
Thread.Sleep(50);
continue;
}
return;
}
// depending on your use case, consider throwing an exception here
}
在我看来,这样的帮助程序应该用于所有删除,因为总是可能的虚假故障。但是,您应该根据用例调整此代码,而不仅仅是盲目复制它。
我的应用程序生成的内部数据文件夹(位于 %LocalAppData% 下)出现了虚假故障,因此我的分析如下所示:
Sleep(0)
Sleep(0)
模板简介:该模板名称为【C#无法使用 Directory.Delete(path, true) 删除目录】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【C#】栏目查找您需要的精美模板。