Question

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.

Était-ce utile?

La solution

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();

Autres conseils

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).

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);

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top