I'm using .NET 3.5, trying to recursively delete a directory using:
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 know the directory is not empty.)
Is there a reason I'd see this instead of AccessViolationException?
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.
Also, MSDN is clear that you don't have to write your own recusion: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx
This is because of FileChangesNotifications.
It happens since ASP.NET 2.0. When you delete some folder within an app, it gets restarted. You can see it yourself, using ASP.NET Health Monitoring.
Just add this code to your web.config/configuration/system.web:
After that check out
Windows Log -> Application
. What is going on:When you delete folder, if there is any sub-folder,
Delete(path, true)
deletes sub-folder first. It is enough for FileChangesMonitor to know about removal and shut down your app. Meanwhile your main directory is not deleted yet. This is the event from Log:Delete()
didn't finish its work and because app is shutting down, it raises an exception:When you do not have any subfolders in a folder that you are deleting, Delete() just deletes all files and that folder, app is getting restarted too, but you don't get any exceptions, because app restart doesn't interrupt anything. But still, you lose all in-process sessions, app doesn't response to requests when restarting, etc.
What now?
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:
Make a controller that handles incoming calls and then serves files back by reading from folder outside an app (outside wwwroot).
If your project is big and performance is most important, set up separate small and fast webserver for serving static content. Thus you will leave to IIS his specific job. It could be on the same machine (mongoose for Windows) or another machine (nginx for Linux). Good news is you don't have to pay extra microsoft license to set up static content server on linux.
Hope this helps.
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.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.
Just slap this code into your project.
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%)
orC:\
.If you are trying to recursively delete directory
a
and directorya\b
is open in Explorer,b
will be deleted but you will get the error 'directory is not empty' fora
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 callDirectory.Delete(true)
, it deletes from bottom up:b
, thena
. Ifb
is open in Explorer, Explorer will detect the deletion ofb
, change directory upwardscd ..
and clean up open handles. Since the file system operates asynchronously, theDirectory.Delete
operation fails due to conflicts with Explorer.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.
But this only works if the open directory is the immediate child of the directory you are deleting. If
a\b\c\d
is open in Explorer and you use this ona
, this technique will fail after deletingd
andc
.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.
Despite the extra work of recursing on our own, we still have 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.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 thetry
block. Additionally, there is a risk that under heavy system load, you could fly through both of theDirectory.Delete
attempts and fail. Consider this solution a starting point for more robust recursive deletion.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,
This innocent statement, supplied with only a link to the NTFS reference documentation, ought to make your hairs stand up.
(Edit: A lot. This answer originally only had the first, incomplete solution.)
One important thing which should be mentioned (I'd added it as a comment but I'm not allowed to) is that the overload's behavior changed from .NET 3.5 to .NET 4.0.
Starting from .NET 4.0 it deletes files in the folder itself but NOT in 3.5. This can be seen in the MSDN documentation as well.
.NET 4.0
.NET 3.5
You can reproduce the error by running:
When trying to delete directory 'b', it throws the IOException "The directory is not empty". That's stupid since we just deleted the directory 'c'.
From my understanding, the explanation is that directory 'c' is stamped as deleted. But the delete is not yet commited in the system. The system has reply the job is done, while in fact, it is still processing. The system probably wait the file explorer has focus on the parent directory to commit the delete.
If you look on the source code of the Delete function (http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs) you will see it uses the native Win32Native.RemoveDirectory function. This do-not-wait behavior is noted here :
(http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx)
Sleep and retry is the solution. Cf the ryascl's solution.