Windows Explorer and Directory.Delete()

It’s probably a common scenario: you’ve got some process that, in the course of doing whatever it does, creates a directory and later deletes that same directory. If you’re working in .NET using C# you might be making a call like this:

Directory.Delete("c:\\Temp\\Test1", true);

While debugging the program you naturally open up Windows explorer and look at the file system to confirm that the program is doing what you expect. But then, for some reason it doesn’t. Instead of removing the specified folder and all its children through recursive deletes the line of code above throws an exception:

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 recur
sive)
at System.IO.Directory.Delete(String path, Boolean recursive)
at DirectoryTest.Program.Main(String[] args) in C:\VSProjects\DirectoryTest\Program.cs:line 31

This happened to me recently while debugging a back-end job, and it took me a few minutes of head scratching before I realized that Explorer was the culprit. Searching around on Google revealed that this little gotcha has nabbed others before me, and in some cases programmers were led to extreme solutions such as creating their own recursive delete method, and for all I know may have done so without ever finding out what the real cause was.

I coded up a little test to try and nail down the behavior. The results were a little bit interesting, and a little bit confusing. The test program just creates a directory ‘Temp’ under C:\, and then creates a two-level directory structure under that consisting of parent folder ‘Test1’ and child folder ‘Test2’. In each test folder it creates a text file, named respectively TestFile1.txt, and TestFile2.txt. It then waits for the user to press a key and attempts to delete the Test1 folder and all its children. If an exception is thrown it is dumped to the screen. You can see the entire listing here.

When you run the program you’ll see that it has created the test directory structure and is awaiting a keypress from you prior to removing it. This pause is so that we can mess with Explorer and try to find out what is causing the exception.

Let’s start by just opening Windows Explorer and confirming that the folders and files were created as specified. Of course, there’s no question that they were, but in a real piece of software the logic might be much more complex, and Explorer might just be the fastest way to confirm what is happening on disk, as it was for me while working on our server job.

You can see the Temp directory I created as a container for the test, and the two test directories underneath it. Test1 is highlighted in the left treeview, so the right-hand view shows the file TestFile1.txt, and the child directory Test2. In order to delete the test directory the program calls a method named DeleteTestDirectory().

static void DeleteTestDirectory()
{
    try
    {
        Console.WriteLine("Deleting test directory");
        Directory.Delete("c:\\Temp\\Test1", true);
    }
    catch (Exception ex)
    {
        DisplayError(ex);
        WaitForKey();
        return;
    }
}

If we return to the test program and press a key, the method executes, Directory.Delete is called with the recursive flag, and we see that the directories are removed as expected.

I italicized the phrase “in the left treeview” above, because I wanted to make a distinction regarding where the focus of input is in the Explorer window. In the previous test the focus was in the left-hand treeview, specifically the active highlight of directory ‘Test1’. Let’s move the focus over to the right-hand pane and try it again.

This also works as expected. Next I tried highlighting the file ‘TestFile1.txt’. When you highlight a file in Explorer it grabs the icon, size, attributes, created and modified dates, etc., and if you are using the preview pane it may grab a snapshot of the contents. For these reasons I suspected that highlighting the file might cause the problem I had seen while debugging our server job. But once again Directory.Delete worked as expected. I next moved down a level in the tree to directory ‘Test2’, and highlighted the file ‘TestFile2.txt’.

This is the exact same scenario as above, but one level lower down in the directory structure. It shouldn’t make a difference, but when you press the key to remove the structure in this case you see the error.

Of course the directory isn’t empty! That’s why I specified a recursive delete! So, what’s going on here? I’m damned if I know. Maybe someone at Microsoft does. I could probably figure out a lot more using System Internals’ file system monitor utility, but I don’t really have time to chase down Explorer’s foibles. I just want to know what can cause my software to fail, and how to prevent it.

It might seem obvious that competing file access can cause such problems, and it is. In most cases where you do this to yourself it doesn’t take a month’s effort to figure it out and fix it. But when it is a side effect of the state of a desktop component like Explorer the cause and solution can be harder to perceive. Speaking of solutions, here is an alternative to the DeleteTestDirectory() method. Let’s call it SafeDeleteTestDirectory().

static void SafeDeleteTestDirectory()
{
    try
    {
        Console.WriteLine("Deleting test directory with retry");
        Directory.Delete("c:\\Temp\\Test1", true);
    }
    catch (Exception ex)
    {
        DisplayError(ex);
        Thread.Sleep(1000);
        Console.WriteLine("Failed! Trying again...");
        try
        {
            Directory.Delete("c:\\Temp\\Test1", true);
        }
        catch (Exception ex2)
        {
            DisplayError(ex2);
            WaitForKey();
            return;
        }
    }
}

What this does is simply react to the first exception by waiting 1000 milliseconds, and then trying again. If the problem recurs we just exit. Interestingly, this works.

However it does seem to give Explorer a case of stomach cramps, which might be a clue to the difference between the scenarios that succeeded, and the one that failed.

So, should you put code like the above into all the places where you call Directory.Delete() with the recursive flag? I’d have to say yes. You might be able to argue against it in the case of a hidden folder, the idea being that if the user can’t open Explorer and see the folder they can’t drill into it and cause this issue. But I don’t think I’d rely on it, personally.

Leave a Reply

Your email address will not be published. Required fields are marked *