0

What I have is a basic program to delete folders created on a given date. The program runs and works however, it's not evaluating sub-directories. Is there something that I am doing wrong or not considering.

Thank you for your help.

Imports System.IO

Public Class FormMain

    Private Sub btn_DeleteFolders_Click(sender As Object, e As EventArgs) Handles btn_DeleteFolders.Click

            Dim myDate As Date = dt_FolderDate.Value.Date
            Dim myRoot As New DirectoryInfo(tb_UNC.Text)

            If tb_UNC.Text Is Nothing Then
                MessageBox.Show("Please select a directory")
            End If

            If Not myRoot.Exists Then
                MessageBox.Show("Directory doesn't exist")
                Exit Sub
            End If


            For Each myDir In myRoot.EnumerateDirectories("*", SearchOption.AllDirectories)
                If myDir.CreationTime.Date = myDate Then
                    myDir.Delete(True)
                End If
            Next
        End If
    End Sub



End Class
BSanders
  • 295
  • 1
  • 6
  • 29
  • Where in your routine did you think that it was "*evaluating subdirectories*"? – RBarryYoung Sep 25 '13 at 14:56
  • I was assuming it was being evaluated in the for loop using the SearchOption.AllDirectories argument. – BSanders Sep 25 '13 at 14:58
  • OK, that is what the Doc says for that search option (poorly named, IMHO). – RBarryYoung Sep 25 '13 at 15:01
  • So if you debug `myRoot.EnumerateDirectories("*", SearchOption.AllDirectories)` it returns an `IEnumerable(Of DirectoryInfo)` with a count of just one? – Karl Anderson Sep 25 '13 at 15:03
  • Should I be using a different naming scheme? Am I doing the search option incorrectly causing to not look at sub directories? I appreciate your time. – BSanders Sep 25 '13 at 15:04
  • @KarlAnderson, If i debug it goes through and will delete any directory that was created on the date chosen but it doesn't evaluate sub-directories. So, if a folder was made and doesn't meet the date criteria it passes over it instead of looking in at the subs to see if they meet the date criteria for deletion. – BSanders Sep 25 '13 at 15:06

2 Answers2

0

If it were me, I'd write a recursive method that I call from my event handler. The method would take as an argument the path to a root directory. Within the method, I'd loop through the sub-directories beneath the provided directory and either a.) delete the sub-directory if needed or b.) recursively call the method on the sub-directory.

Something like this:

Private Sub Recurse(OnFolderPath As String)
    For Each strSubDir In Directory.GetDirectories(OnFolderPath)
        If (New DirectoryInfo(strSubDir).CreationTime.Date = MyDate) Then
            Directory.Delete(strSubDir)
        Else
            Recurse(strSubDir)
        End If
    Next
End Sub

and if you want to avoid problems with reparse points (a.k.a. junction points), as bhs points out, you could include a function like this:

Public Function IsJunctionPoint(ByVal ToCheck As DirectoryInfo) As Boolean
    'if the directory has the attributes which indicate that it's a junction point...
    If (((ToCheck.Attributes And FileAttributes.Hidden) = FileAttributes.Hidden) And
        ((ToCheck.Attributes And FileAttributes.System) = FileAttributes.System) And
        ((ToCheck.Attributes And FileAttributes.ReparsePoint) = FileAttributes.ReparsePoint)) Then

        Return True
    Else 'is not a junction point...
        Return False
    End If
End Function

Then you would just use that from within your recursive method to avoid those.

rory.ap
  • 34,009
  • 10
  • 83
  • 174
0

You've also stumbled (or will do shortly) on a problem I came across just recently.

If you try to enumerate across a file or folder that you don't have permissions on the EnumerateDirectories or EnumerateFolders method will simply stop and throw an exception.

Trapping the exception will also cause it to stop. This is almost certainly not the behaviour you want.

I found a recursive solution on here and implemented a method on this SO page called FindAccessableFiles (I think it might be the last incarnation) and it works extremely well.

private static IEnumerable<String> FindDeletableFolders(string path, string file_pattern, bool recurse)
        {
            IEnumerable<String> emptyList = new string[0];

            if (File.Exists(path))
                return new string[] { path };

            if (!Directory.Exists(path))
                return emptyList;

            var top_directory = new DirectoryInfo(path);

            // Enumerate the files just in the top directory.
            var files = top_directory.EnumerateFiles(file_pattern).ToList();
            var filesLength = files.Count();
            var filesList = Enumerable
                      .Range(0, filesLength)
                      .Select(i =>
                      {
                          string filename = null;
                          try
                          {
                              var file = files.ElementAt(i);
                              filename = file.Name; // add your date check here                              }
                          catch (FileNotFoundException)
                          {
                          }
                          catch (UnauthorizedAccessException)
                          {
                          }
                          catch (InvalidOperationException)
                          {
                              // ran out of entries
                          }
                          return filename;
                      })
                      .Where(i => null != i);

            if (!recurse)
                return filesList;

            var dirs = top_directory.EnumerateDirectories("*");
            var dirsLength = dirs.Count();
            var dirsList = Enumerable
                .Range(0, dirsLength)
                .SelectMany(i =>
                {
                    string dirname = null;
                    try
                    {
                        var dir = dirs.ElementAt(i);
                        dirname = dir.FullName;
                        if (dirname.Length > 0)
                        {
                            var folderFiles = FindDeletableFolders(dirname, file_pattern, recurse).ToList();
                            if (folderFiles.Count == 0)
                            {
                                try
                                {
                                        Directory.Delete(dirname);
                                }
                                catch
                                {
                                }
                            }
                            else
                            {
                                return folderFiles;
                            }
                        }
                    }
                    catch (UnauthorizedAccessException)
                    {
                    }
                    catch (InvalidOperationException)
                    {
                        // ran out of entries
                    }
                    return emptyList;
                });
            return Enumerable.Concat(filesList, dirsList).ToList();
        }

I had to hack some of my code out so check the function and test it before use.

The code will return a list of folders that can be deleted and also delete empty folders it comes across.

Community
  • 1
  • 1
SteveB
  • 1,474
  • 1
  • 13
  • 21