1

Consider this simple program:

private static void Main(string[] args)
{
        var directoryName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Directory");

        if (Directory.Exists(directoryName))
            Directory.Delete(directoryName, true);

        Directory.CreateDirectory(directoryName);

        var stream = File.Create(Path.Combine(directoryName, "File")); //throws
        stream.Close();
}

This works fine while you simply execute this program. The strange thing happens if you browse that Directory in windows explorer and then run. In this case I get UnautorizedAccessException "Access to the path 'C:\Users\rfurman\AppData\Roaming\Directory\File' is denied."

If this is strange then execute this with the same conditions:

private static void Main(string[] args)
{
        var directoryName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Directory");

        if (Directory.Exists(directoryName))
            Directory.Delete(directoryName, true);

        var value = Directory.Exists(directoryName);

        Console.WriteLine(value);
        Console.ReadKey();
 }

This program prints True if Directory is open in explorer.

What I would like to know is why this happens and how to defend against such situation.

I use windows 7 and .net 4.

Rafal
  • 12,391
  • 32
  • 54
  • " if you browse that Directory" what does it mean ? – Saurabh R S Oct 09 '12 at 11:02
  • @Luftwaffe: Open that folder in windows explorer – Rafal Oct 09 '12 at 11:03
  • so you mean.. the folder in kept open in explorer.. right? – Saurabh R S Oct 09 '12 at 11:04
  • It is open while program executes. – Rafal Oct 09 '12 at 11:05
  • And the folder really gets deleted ? – Milind Thakkar Oct 12 '12 at 05:48
  • Folder gets deleted. Try it yourself. – Rafal Oct 12 '12 at 06:39
  • Could not reproduce [ http://xkcd.com/583/ ] Really, I don't get the exception, the directory gets deleted in the first case and it says false in the second regardless of accesding the folder in explorer. Yes the folder remains open, even though it is being deleted and created again, it is just to fast for Explorer to notice it (you can add Thread.Sleep(10000) after deleting before creating and Explroer should leave the folder). I use Windows 7 and .net 4.5. Fixed in .NET 4.5? – Theraot Oct 12 '12 at 07:28
  • Explorer is not an issue. The weirdness is in .net (4 in my case) that after ordering folder deletion returns that this folder exists. And that strange access exception. And referenced story just suggests bad testers. – Rafal Oct 12 '12 at 08:08

4 Answers4

3

This is somewhat of a duplicate: Bizarre directory delete behaviour on SSD drive

The explorer is just causing a slightly longer delay in the folder delete. Deleting a directory is not 'exactly' a synchronous operation. The directory is marked for deletion but the actual delete may lag a bit.

AFAIK this has been around as long as NTFS (win2k/Xp).

Community
  • 1
  • 1
csharptest.net
  • 62,602
  • 11
  • 71
  • 89
2

Directory.Delete internally uses RemoveDirectory win api in Kernel32. What RemoveDirectory does is "to mark directory for deletion". Directory is deleted when last handle of that directory is closed. I believe this means "after explorer left that folder"

In my computer this situation does not occur, so I cannot test but I suspect there may be a way for you. NT based systems sometimes allows renaming of files and directories even if they are open. I don't know exact cases this is allowed, but I used this to rename loaded dll files and write new ones like this:

File.Rename(@"C:\App\test.dll", @"C:\App\test.dll");
File.Copy(@"C:\App\Update\test.dll-v1.1", @"C:\App\test.dll");

So your code may look like this after change

var directoryName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Directory");

if (Directory.Exists(directoryName)) {
    var randomExt = ".random"; // generate randomly
    Directory.Move(directoryName, directoryName + randomExt)
    Directory.Delete(directoryName + randomExt, true);
}
Directory.CreateDirectory(directoryName);

var stream = File.Create(Path.Combine(directoryName, "File")); //throws
stream.Close();
Erdogan Kurtur
  • 3,630
  • 21
  • 39
  • OK your solution works, but it seams as a hack. Directory.Delete method documentation clearly states that method deletes folder and its content. There is no fraction of information that it might be asynchronous. I simply cannot accept that it is asynchronous. Can you reference some article that proves what you are implying? – Rafal Oct 12 '12 at 12:02
  • Sorry for disappointment. To prove `Directory.Delete` uses RemoveDirectory you have to use ILSpy. RemoveDirectory documentation can be accessed at http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx .Just look at comments section. – Erdogan Kurtur Oct 12 '12 at 12:06
0

This problem surprised me as well. My alternative, which is a different kludge:

    if (Directory.Exists(directoryName))
    {
        Directory.Delete(directoryName, true);
        while (Directory.Exists(directoryName))
            Thread.Sleep(100);
    }

    Directory.CreateDirectory(directoryName);
JNay
  • 1
-1

In some cases, if you have the specified directory open in File Explorer, the Delete method may not be able to delete it.

Reference: Directory.Delete Method

Saurabh R S
  • 3,037
  • 1
  • 34
  • 44
  • delete succeeded but results are observable with delay – Rafal Oct 09 '12 at 11:21
  • In the MSDN Reference there's a list of conditions where `Directory.Delete` would throw `IOException`. And even to my surprise this condition (Folder is open in Explorer) is not handled by it. But in `Remarks` section they have mentioned that in some cases, if you have the specified directory open in File Explorer, the Delete method may not be able to delete it. – Saurabh R S Oct 09 '12 at 11:23
  • This is not the case. Directory gets deleted. – Rafal Oct 09 '12 at 11:27