none
System.IO.Directory.Delete(string path, bool recursive) doesn't seem to be blocking (on Windows 7) if Windows Explorer has a handle

    Question

  • Please help!

    My perceived understanding of a rather simple System.IO.Directory.Delete() method is shattered to pieces. I always thought that calls to Delete are blocking (meaning, it will not return until the directory is deleted or an exception is thrown). But here what I noticed that all changed when the following caused an exception in the using statement:

    if (System.IO.Directory.Exists(directoryName))
    {
       System.IO.Directory.Delete(directoryName, true);
    }
    
    System.IO.Directory.CreateDirectory(directoryName);
    
    string fileName = directoryName + "\\" +"file.xml";
    using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(fileName))
    {
    }
    
     

    Spending some time debugging this, I realized that what's happening is absolutely maddening, if you assume the Delete() is blocking. It seems that if the Delete() task takes some time (in my case, the directory contains about 5,000 small 1KB files), Delete returns before completing. The following call to CreateDirectory() doesn't fail, even though technically, the directory in question is still there, but by the time I am ready to use the directory, it's gone!

    A simple addition of Sleep(2000) after Delete and before CreateDirectory ensured that by the time I am ready to create a file, the directory exists.

    Still not believing what I saw, I wrote an app to crudely monitor this behavior. So, instead of a Sleep(), I am actually sitting in a loop while the directory is still there. And sure thing, on my box it takes about 200 ms for the directory to be reported as "doesn't exist" after the return of Delete.

    I am running this sample app (see below) on Windows 7, with about 5,000 files to create.

    Now, the bizarre part is that if I don't have a Windows Explorer open in the directory in question, everything works as expected. But, if I manually create the directory, navigate there with Windows Explorer and then run my app -- voila. You will see messages in the console window, stating that it's still waiting for deletion to complete, which proves that while Delete() is done, Exists() still finds the directory there.

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace TestDelete
    {
      class Program
      {
        static void Main(string[] args)
        {
          const string testDirectory = @"c:\\MyTest\\Test1";
          const int fileCount = 5000;
    
          Console.WriteLine("Creating {0} files...", fileCount);
          CreateFiles(testDirectory, fileCount);
    
          PrepareDirectory(testDirectory);
    
          Console.WriteLine("Press any key to continue...");
          Console.Read();
        }
    
        static void CreateFiles(string directoryName, int fileCount)
        {
          if (!System.IO.Directory.Exists(directoryName))
          {
            System.IO.Directory.CreateDirectory(directoryName);
          }
          
          for (int i = 0; i < fileCount; i++)
          {
            string fileName = directoryName + "\\" + i.ToString() + ".xml";
            using (System.Xml.XmlWriter xw = System.Xml.XmlTextWriter.Create(fileName))
            {
            }
          }
        }
    
        static void PrepareDirectory(string directoryName)
        {
          if (System.IO.Directory.Exists(directoryName))
          {
            Console.WriteLine("Directory {0} exists -- delete it", directoryName);
            System.IO.Directory.Delete(directoryName, true);
            Console.WriteLine("Delete returned");
          }
    
          WaitForDeletion(directoryName);
        }
    
        static void WaitForDeletion(string directoryName)
        {
          bool deleted = false;
    
          do
          {
            deleted = !System.IO.Directory.Exists(directoryName);
    
            DateTime now = DateTime.Now;
            Console.WriteLine("{0} Directory {1} is {2}",
              now.Minute.ToString("00") + ":" + now.Second.ToString("00") + "." + now.Millisecond.ToString("000"),
              directoryName,
              deleted ? "deletion complete" : "still waiting for deletion");
    
            System.Threading.Thread.Sleep(100);
          } while (!deleted);
        }
      }
    }
    

     

    Any ideas what's going on? Is that a bug? Any input is greatly appreciated.

    Thanks,

    VR


    Regards, VRSki
    Wednesday, May 05, 2010 5:55 PM

Answers

  • You can either click on "Send feedback on this topic to Microsoft" on your local help (bottom of each page), submit a comment on the msdn help page (for example here ) by scrolling down to Community content, or open a case at Connect .

    Cristian.

    Thursday, May 06, 2010 12:12 PM

All replies

  • System.IO.Directory.Delete ultimately (after removing the files) calls native RemoveDirectory , which will mark a directory to be deleted. Acording to docs: "Therefore, the directory is not removed until the last handle to the directory is closed.".

    Not being too conversant in native code, I'm not sure if the "last handle" mentioned refers to the handles hold by the application doing the call or to any open handles. Your result would indicate the latter.

    Either way, a remark in the documentation would probably save hours of debugging... maybe something to ask for in connect.microsoft.com ?

    Cristian.

    Wednesday, May 05, 2010 6:31 PM
  • See http://msdn.microsoft.com/en-us/library/62t64db3.aspx

    or http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx

    They both mention this:

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

     


    http://blog.voidnish.com
    Wednesday, May 05, 2010 6:51 PM
  • Good to see that Explorer interacting was already added to the NET 4.0 docs. Still, the (possible) delay probably needs to be documented to.

    Cristian.

    Wednesday, May 05, 2010 7:00 PM
  • Thank you for the replies.

    This all makes sense. I understand that simply calling Delete cannot ensure that the directory is removed. But at the same time, I'd expect some kind of a feedback, like an exception.

    If the way to make sure that the directory is deleted is to keep checking whether it exists after calling Delete(), then I'd expect to see bunch of discussions on forums about correct coding patterns for deletion, describing the best way to wait for the handle to become invalid or something like that. Or ultimately, this should have been part of the API, allowing users to choose to call Delete synchronously or asynchronously, where the synchronous way would guarantee the directory is gone.

    So, I guess to me the question still remains. Does "In some cases, if you have the specified directory open in Windows Explorer, the Delete method may not be able to delete it" mean that users should be prepared to catch an exception if Windows Explorer indeed has the specified directory open and what I see is a bug, or Delete doesn't throw in this case by design.

    And if the behavior I am seeing is by design, what is the expect coding pattern to make sure the directory is gone?

    Thanks again,

    VR


    Regards, VRSki
    Wednesday, May 05, 2010 9:43 PM
  • I also think that the sentence "In some cases..." is a rather lame formulation of a problem (at least they should mention the Exception expected or, if none is thrown, the observed behaviour.

    I would also say that the delay you observed is a different topic, that also needs to be documented. Since this is just a forum (not an official reporting tool), why not open a request for documentation at Connect? They usually answer pretty fast.

    Cristian.

    Wednesday, May 05, 2010 10:31 PM
  • Sounds like a good idea. I've never done anything through Connect. Do you have a link for that by any chance?

     

    Thanks again.

    VR


    Regards, VRSki
    Wednesday, May 05, 2010 11:56 PM
  • You can either click on "Send feedback on this topic to Microsoft" on your local help (bottom of each page), submit a comment on the msdn help page (for example here ) by scrolling down to Community content, or open a case at Connect .

    Cristian.

    Thursday, May 06, 2010 12:12 PM