我使用。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)
...
我并不惊讶于这个方法有时会抛出错误,但我惊讶于当递归为真时得到这个特定的消息。(我知道目录不是空的。)
是否有一个原因,我将看到这个而不是AccessViolationException?
编者注:尽管这个答案包含了一些有用的信息,但关于Directory.Delete的工作原理实际上是不正确的。请阅读这个答案的评论,以及这个问题的其他答案。
我以前遇到过这个问题。
The root of the problem is that this function does not delete files that are within the directory structure. So what you'll need to do is create a function that deletes all the files within the directory structure then all the directories before removing the directory itself. I know this goes against the second parameter but it's a much safer approach. In addition, you will probably want to remove READ-ONLY access attributes from the files right before you delete them. Otherwise that will raise an exception.
只需将这些代码放入您的项目中。
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:\。
如上所述,“可接受的”解决方案在重解析点上失败。
有一个更短的解决方案可以正确地复制功能:
public static void rmdir(string target, bool recursive)
{
string tfilename = Path.GetDirectoryName(target) +
(target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
Path.GetRandomFileName();
Directory.Move(target, tfilename);
Directory.Delete(tfilename, recursive);
}
我知道,不能处理后面提到的权限情况,但是FAR BETTER提供了原始/stock Directory.Delete()的预期功能,而且代码也少得多。
您可以安全地进行处理,因为旧的dir将被清除……即使没有消失,因为“文件系统仍在追赶”(或任何借口,微软提供了一个坏的功能)。
作为一个好处,如果你知道你的目标目录是大/深的,并且不想等待(或麻烦的异常),最后一行可以替换为:
ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });
你仍然可以安全地继续工作。
这是因为FileChangesNotifications。
它发生在ASP。NET 2.0。当你删除应用程序中的某个文件夹时,它会重新启动。你可以自己看,用
ASP。NET运行状况监视。
只需将这段代码添加到你的web.config/configuration/system.web:
<healthMonitoring enabled="true">
<rules>
<add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
</rules>
</healthMonitoring>
之后,检查Windows Log ->应用程序。
发生了什么:
删除文件夹时,如果有子文件夹,delete (path, true)会先删除子文件夹。这足以让FileChangesMonitor知道删除和关闭你的应用程序。同时你的主目录还没有删除。这是来自日志的事件:
Delete()没有完成它的工作,因为应用程序正在关闭,它引发了一个异常:
当你正在删除的文件夹中没有任何子文件夹时,Delete()只是删除所有文件和该文件夹,app也会重新启动,但你不会得到任何异常,因为app重新启动不会中断任何事情。但是,你仍然会失去所有进程中的会话,应用程序在重新启动时不响应请求,等等。
现在该做什么?
There are some workarounds and tweaks to disable this behaviour, Directory Junction, Turning Off FCN with Registry, Stopping FileChangesMonitor using Reflection (since there is no exposed method), but they all don't seem to be right, because FCN is there for a reason. It is looking after structure of your app, which is not structure of your data. Short answer is: place folders you want to delete outside of your app. FileChangesMonitor will get no notifications and your app will not be restarted every time. You will get no exceptions. To get them visible from the web there are two ways:
创建一个控制器来处理传入调用,然后通过从应用程序外部(wwwroot外部)的文件夹读取文件返回。
如果你的项目很大,性能是最重要的,那就单独设置一个小型快速的web服务器来提供静态内容。因此,您将把他的具体工作留给IIS。它可以在同一台机器上(Windows的mongoose),也可以在另一台机器上(Linux的nginx)。好消息是你不需要支付额外的微软许可证来在linux上设置静态内容服务器。
希望这能有所帮助。
您可以通过运行以下命令来重现错误:
Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");
当试图删除目录'b'时,它抛出IOException“目录不是空的”。这很愚蠢,因为我们刚刚删除了目录'c'。
在我的理解中,解释是目录'c'被标记为已删除。但是系统中还没有提交删除操作。系统已经回复任务已经完成,而实际上它还在处理中。系统可能会等待文件资源管理器已经关注到父目录才提交删除。
如果你查看删除函数(http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs)的源代码,你会发现它使用本机Win32Native。RemoveDirectory函数。这种不等待行为在这里被注意到:
RemoveDirectory函数在关闭时标记要删除的目录。因此,直到关闭该目录的最后一个句柄,才会删除该目录。
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488 (v = vs.85) . aspx)
休眠和重试是解决方案。参考ryascl的溶液。