1

In my program, I create a long branching tree of directories. When I'm done with certain files on the leaves of this tree, I delete them, but I end up with a lot of empty parent directories. I'd like to delete these as well. However, I can't just recursively delete all these parent directories, because some of them have children that I can't delete yet.

Example: C:\MyProject\Project1\file1\file2\file3\file4\file5\document.txt

If I delete document.txt, I want to also delete all the other empty folders in the path. However, file 3 has something in it (besides file4), so I can't delete it or anything above it. So in this case, file4 and file5 would be deleted.

Consider the root directory to be Project1. I don't want to delete anything above that.

Has anyone written something to do this?

Basically, something I can call where I can specify the path I'm trying to remove from the tree (first arg below), along with the root of the tree (second arg).

DeleteEmptySubDirectoriesInPath("C:\MyProject\Project1\file1\file2\file3\file4\file5\",
"C:\MyProject\Project1");

Another way to look at it is the inverse of Directory.CreateDirectory. This is the function I used to generate these long branches. Now I need to remove them when I'm done without disturbing anything else.

NielW
  • 3,626
  • 1
  • 30
  • 38
  • 1
    Will this work? http://stackoverflow.com/a/2811654/2855568 – DeveloperGuo Mar 20 '14 at 00:05
  • @NielW Make sure you use the `EnumerateFileSystemEntries` suggestion in the comments of the question that @DeveloperGuo linked. – NathanAldenSr Mar 20 '14 at 00:06
  • That's sort of the idea. I actually looked there first. The problem with that approach is it's top down, and will delete other empty directories that are not in the path I'm trying to delete. – NielW Mar 20 '14 at 00:06

2 Answers2

6

A little bit of iteration would work:

var di = new DirectoryInfo(@"C:\MyProject\Project1\file1\file2\file3\file4\");
var root = @"C:\MyProject\Project1"; // no trailing slash!
while (di.FullName != root 
       && !di.EnumerateFiles().Any() 
       && !di.EnumerateDirectories().Any())
{
    di.Delete();
    di = di.Parent;
}

Start from the directory of interest; as long as there are no files and you have not reached the "root", delete it and move to its parent directory. Repeat until done.

Jon
  • 428,835
  • 81
  • 738
  • 806
  • This is great, but it throws if there are any subfolders in the directory being deleted. I added " && !di.EnumerateDirectories().Any()" to the while clause, and it works great. I sugggest updating your answer so I can select it. – NielW Mar 20 '14 at 16:27
  • @NielW: Hm, I thought you would be always starting from a leaf directory. Sure, going to update. – Jon Mar 20 '14 at 16:41
  • I am, but some of the parents have other children. When I say "the directory being deleted", I'm referring to your "di". – NielW Mar 20 '14 at 17:05
2

Doesn't seem like it should be any more difficult than this:

  • We delete the file
  • Walk up the directory tree, deleting [empty] directories as we go until we get to the root.

Here's the code:

static void DeleteAndPrune(string path)
{
  FileInfo fi = new FileInfo(path);
  fi.Delete();

  // the loop ends with the first non-empty directory, or the root.
  // - if the directoryInfo itself is null, the file was deleted *from* the root,
  //   so there's nothing to do.
  // - if the directoryInfo's parent is null, we've hit the root directory
  // Easy!      
  for ( DirectoryInfo di = fi.Directory ; di != null && di.Parent != null && !di.EnumerateFileSystemInfos().Any() ; di = di.Parent )
  {
    di.Delete() ;
  }

  return;
}

It's almost simpler if you want to just walk the entire tree and tidy it to remove empty directories. Just a simple recursive tree walk:

    static void Tidy( DirectoryInfo tree )
    {
        foreach (DirectoryInfo di in tree.EnumerateDirectories())
        {
            Tidy(di);
        }
        tree.Refresh();
        if (!tree.EnumerateFileSystemInfos().Any())
        {
            tree.Delete();
        }
        return;
    }

That can be done like so:

DirectoryInfo root = new DirectoryInfo( @"C:\MyProject\Project1" ) ;
Tidy(root) ;
Nicholas Carey
  • 71,308
  • 16
  • 93
  • 135