C# 无法使用 Directory.Delete(path, true) 删除目录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/329355/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot delete directory with Directory.Delete(path, true)
提问by Jason Anderson
I'm using .NET 3.5, trying to recursively delete a directory using:
我正在使用 .NET 3.5,尝试使用以下方法递归删除目录:
Directory.Delete(myPath, true);
My understanding is that this should throw if files are in use or there is a permissions problem, but otherwise it should delete the directory and all of its contents.
我的理解是,如果文件正在使用或存在权限问题,这应该抛出,否则它应该删除目录及其所有内容。
However, I occasionally get this:
但是,我偶尔会得到这个:
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)
...
I'm not surprised that the method sometimes throws, but I'm surprised to get this particular message when recursive is true. (I knowthe directory is not empty.)
我对这个方法有时会抛出并不感到惊讶,但是当 recursive 为 true 时,我很惊讶收到这个特定的消息。(我知道目录不是空的。)
Is there a reason I'd see this instead of AccessViolationException?
有什么理由让我看到这个而不是 AccessViolationException?
回答by Drejc
I had the very same problem under Delphi. And the end result was that my own application was locking the directory I wanted to delete. Somehow the directory got locked when I was writing to it (some temporary files).
我在 Delphi 下遇到了同样的问题。最终结果是我自己的应用程序锁定了我想删除的目录。当我写入目录(一些临时文件)时,不知何故该目录被锁定。
The catch 22 was, I made a simple change directoryto it's parent before deleting it.
问题 22 是,在删除它之前,我对其父目录做了一个简单的更改。
回答by Douglas Leeder
Is it possible you have a race condition where another thread or process is adding files to the directory:
您是否可能遇到竞争条件,其中另一个线程或进程正在向目录添加文件:
The sequence would be:
顺序是:
Deleter process A:
删除进程A:
- Empty the directory
- Delete the (now empty) directory.
- 清空目录
- 删除(现在是空的)目录。
If someone else adds a file between 1 & 2, then maybe 2 would throw the exception listed?
如果其他人在 1 和 2 之间添加了一个文件,那么 2 可能会抛出列出的异常?
回答by Vilx-
The directory or a file in it is locked and cannot be deleted. Find the culprit who locks it and see if you can eliminate it.
目录或其中的文件被锁定,无法删除。找到锁定它的罪魁祸首,看看是否可以消除它。
回答by Jeremy Edwards
Editor's note:Although this answer contains some useful information, it is factually incorrect about the workings of Directory.Delete
. Please read the comments for this answer, and other answers to this question.
编者按:虽然这个答案包含了一些有用的信息,但实际上关于Directory.Delete
. 请阅读此答案的评论以及此问题的其他答案。
I ran into this problem before.
我之前遇到过这个问题。
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.
问题的根源在于该功能不会删除目录结构内的文件。因此,您需要做的是创建一个函数,在删除目录本身之前先删除目录结构中的所有文件,然后删除所有目录。我知道这与第二个参数背道而驰,但这是一种更安全的方法。此外,您可能希望在删除文件之前立即从文件中删除 READ-ONLY 访问属性。否则会引发异常。
Just slap this code into your project.
只需将此代码添加到您的项目中即可。
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);
}
Also, for me I personally add a restriction on areas of the machine that are allowed to be deleted because do you want someone to call this function on C:\WINDOWS (%WinDir%)
or C:\
.
另外,对我而言,我个人对允许删除的机器区域添加了限制,因为您是否希望有人在C:\WINDOWS (%WinDir%)
或上调用此功能C:\
。
回答by configurator
If your application's (or any other application's) current directory is the one you're trying to delete, it will not be an access violation error but a directory is not empty. Make sure it's not your own application by changing the current directory; also, make sure the directory is not open in some other program (e.g. Word, excel, Total Commander, etc.). Most programs will cd to the directory of the last file opened, which would cause that.
如果您的应用程序(或任何其他应用程序)的当前目录是您要删除的目录,则不会是访问冲突错误,但目录不是空的。通过更改当前目录确保它不是您自己的应用程序;此外,请确保该目录未在其他程序(例如 Word、excel、Total Commander 等)中打开。大多数程序会 cd 到最后打开的文件所在的目录,这会导致这种情况。
回答by configurator
I had a those weird permission problems deleting User Profile directories (in C:\Documents and Settings) despite being able to do so in the Explorer shell.
尽管能够在资源管理器外壳中删除用户配置文件目录(在 C:\Documents and Settings 中),但我遇到了那些奇怪的权限问题。
File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);
It makes no sense to me what a "file" operation does on a directory, but I know that it works and that's enough for me!
“文件”操作对目录的作用对我来说毫无意义,但我知道它可以工作,这对我来说就足够了!
回答by ryscl
If you are trying to recursively delete directory a
and directory a\b
is open in Explorer, b
will be deleted but you will get the error 'directory is not empty' for a
even though it is empty when you go and look. The current directory of any application (including Explorer) retains a handle to the directory. When you call Directory.Delete(true)
, it deletes from bottom up: b
, then a
. If b
is open in Explorer, Explorer will detect the deletion of b
, change directory upwards cd ..
and clean up open handles. Since the file system operates asynchronously, the Directory.Delete
operation fails due to conflicts with Explorer.
如果您尝试递归删除目录a
并且目录a\b
在资源管理器中打开,b
则将被删除,但您会收到错误“目录不是空的”,a
即使您去查看时它是空的。任何应用程序(包括资源管理器)的当前目录都保留了该目录的句柄。当您调用 时Directory.Delete(true)
,它会自下而上删除:b
,然后a
。如果b
在资源管理器中打开,资源管理器将检测到 的删除b
,向上更改目录cd ..
并清理打开的句柄。由于文件系统是异步Directory.Delete
运行的,与资源管理器冲突导致运行失败。
Incomplete solution
不完整的解决方案
I originally posted the following solution, with the idea of interrupting the current thread to allow Explorer time to release the directory handle.
我最初发布了以下解决方案,其想法是中断当前线程以允许资源管理器有时间释放目录句柄。
// incomplete!
try
{
Directory.Delete(path, true);
}
catch (IOException)
{
Thread.Sleep(0);
Directory.Delete(path, true);
}
But this only works if the open directory is the immediatechild of the directory you are deleting. If a\b\c\d
is open in Explorer and you use this on a
, this technique will fail after deleting d
and c
.
但这仅在打开的目录是您要删除的目录的直接子目录时才有效。如果a\b\c\d
在资源管理器中打开并且您在 上使用它a
,则删除d
和后此技术将失败c
。
A somewhat better solution
一个更好的解决方案
This method will handle deletion of a deep directory structure even if one of the lower-level directories is open in Explorer.
即使在资源管理器中打开了较低级别的目录之一,此方法也将处理深层目录结构的删除。
/// <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);
}
}
Despite the extra work of recursing on our own, we stillhave to handle the UnauthorizedAccessException
that can occur along the way. It's not clear whether the first deletion attempt is paving the way for the second, successful one, or if it's merely the timing delay introduced by the throwing/catching an exception that allows the file system to catch up.
尽管我们自己进行了额外的递归工作,但我们仍然必须处理UnauthorizedAccessException
沿途可能发生的问题。尚不清楚第一次删除尝试是否为第二次成功的删除尝试铺平了道路,或者仅仅是抛出/捕获异常引入的时间延迟允许文件系统赶上。
You might be able to reduce the number of exceptions thrown and caught under typical conditions by adding a Thread.Sleep(0)
at the beginning of the try
block. Additionally, there is a risk that under heavy system load, you could fly through both of the Directory.Delete
attempts and fail. Consider this solution a starting point for more robust recursive deletion.
您可以通过Thread.Sleep(0)
在try
块的开头添加一个来减少在典型条件下抛出和捕获的异常数量。此外,还有一种风险,即在系统负载较重的情况下,您可能会Directory.Delete
尝试两次并失败。将此解决方案视为更强大的递归删除的起点。
General answer
一般回答
This solution only addresses the peculiarities of interacting with Windows Explorer. If you want a rock-solid delete operation, one thing to keep in mind is that anything (virus scanner, whatever) could have an open handle to what you are trying to delete, at any time. So you have to try again later. How much later, and how many times you try, depends on how important it is that the object be deleted. As MSDN indicates,
此解决方案仅解决与 Windows 资源管理器交互的特殊性。如果你想要一个坚如磐石的删除操作,要记住的一件事是,任何东西(病毒扫描程序,无论什么)都可以随时打开你要删除的东西的句柄。所以你必须稍后再试。多长时间后,您尝试多少次,取决于删除对象的重要性。正如MSDN 指出的那样,
Robust file iteration code must take into account many complexities of the file system.
健壮的文件迭代代码必须考虑到文件系统的许多复杂性。
This innocent statement, supplied with only a link to the NTFS reference documentation, ought to make your hairs stand up.
这个无辜的声明,只提供了一个指向 NTFS 参考文档的链接,应该会让你毛骨悚然。
(Edit: A lot. This answer originally only had the first, incomplete solution.)
(编辑:很多。这个答案最初只有第一个不完整的解决方案。)
回答by David Alpert
It appears that having the path or subfolder selected in Windows Explorer is enough to block a single execution of Directory.Delete(path, true), throwing an IOException as described above and dying instead of booting Windows Explorer out to a parent folder and proceding as expected.
似乎在 Windows 资源管理器中选择路径或子文件夹足以阻止 Directory.Delete(path, true) 的单次执行,如上所述抛出 IOException 并死亡而不是将 Windows 资源管理器启动到父文件夹并继续执行预期的。
回答by crowdy
in case of network files, Directory.DeleteHelper(recursive:=true) might cause IOException which caused by the delay of deleting file
如果是网络文件,Directory.DeleteHelper(recursive:=true) 可能会导致 IOException,这是由删除文件的延迟引起的
回答by GrokSrc
I had this problem today. It was happening because I had windows explorer open to the directory that was trying to be deleted, causing the recursive call the fail and thus the IOException. Make sure there are no handles open to the directory.
我今天遇到了这个问题。发生这种情况是因为我将 Windows 资源管理器打开到试图删除的目录,导致递归调用失败,从而导致 IOException。确保没有打开目录的句柄。
Also, MSDN is clear that you don't have to write your own recusion: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx
此外,MSDN 很清楚您不必编写自己的回避:http: //msdn.microsoft.com/en-us/library/fxeahc5f.aspx