1

I have the following code, it finds and displays empty folders, unfortunately it can't handle all folders, The Recycle bin and the App data folder cause access exceptions.

Further down is an example from another user that uses enumeration, with it I can access restricted folders but it can't handle long paths.

I'm trying the Delimon.Win32.IO; namespace from http://gallery.technet.microsoft.com/scriptcenter/DelimonWin32IO-Library-V40-7ff6b16c It can apparently handle long paths (I've not tested it yet)

I need a solution that can handle access restrictions and long paths - if possible.

private void button1_Click(object sender, EventArgs e)
    {
        //Open folder browser for user to select the folder to scan
        DialogResult result = folderBrowserDialog1.ShowDialog();
        if (result == DialogResult.OK)
        {
            //Clear text fields
            listBoxResults.Items.Clear();
            listBoxPath.Items.Clear();
            txtFoldersFound.Clear();

            //Store selected folder path
            string dirPath = folderBrowserDialog1.SelectedPath;

            //Process the folder
            try
            {
                foreach (string dir in Directory.GetDirectories(dirPath, "*.*", SearchOption.AllDirectories))
                {
                    //Populate List Box with all folders found
                    this.Invoke(new Action(() => listUpdate2(dir)));
                    if (Directory.GetDirectories(dir).Length.Equals(0))
                    {
                        //Populate List Box with all empty folders found
                        this.Invoke(new Action(() => listUpdate1(dir + Environment.NewLine)));
                    }
                }
                //Count of the empty folders
                txtFoldersFound.Text = listBoxResults.Items.Count.ToString();
            }
            //Catch exceptions, seems to be folders not accessible causing this. Recycle Bin, App Data etc
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
    }
  • Start to replace the GetDirectories with [EnumerateDirectories](http://msdn.microsoft.com/en-us/library/dd383304(v=vs.110).aspx). And then could you explain if the problem is just the crash when you try to read reserved system directories like the RecycleBin or if there is some other propblem? – Steve Sep 26 '14 at 16:30
  • Hi Steve, Length doesn't appear to be an option with EnumerateDirectories. It doesn't like Directory.EnumerateDirectories(dir).Length.Equals(0)) –  Sep 26 '14 at 16:35
  • @RockE70: In your if condition add this condition, like this - `if (Directory.GetDirectories(dir).Length.Equals(0) || Directory.GetFiles(dir).Length.Equals(0))` – Krishnraj Rana Sep 26 '14 at 16:42
  • @KrishnrajRana - shouldn't that be an `&&` rather than `||`? – petelids Sep 26 '14 at 16:43
  • @petelids: Oh! yes it should &&. Thanks for pointing out... – Krishnraj Rana Sep 26 '14 at 16:46
  • 1
    Well, EnumerateDirectories returns an IEnumerable so you should use Any() – Steve Sep 26 '14 at 16:49
  • @KrishnrajRana I've tried that example as well with no luck. –  Sep 27 '14 at 04:14

1 Answers1

0

It seems that enumerating directories is still a problem in .NET 4.5:

https://connect.microsoft.com/VisualStudio/feedback/details/512171/directory-enumeratedirectory-etc-unusable-due-to-frequent-unauthorizedaccessexceptions-even-runas-administrator

The supplied code uses recursion to traverse the directory structure.

private void button1_Click(object sender, EventArgs e)
    {
        //Open folder browser for user to select the folder to scan
        DialogResult result = folderBrowserDialog1.ShowDialog();
        if (result == DialogResult.OK)
        {
            //Clear text fields
            listBoxResults.Items.Clear();
            listBoxPath.Items.Clear();
            txtFoldersFound.Clear();

            //Store selected folder path
            string dirPath = folderBrowserDialog1.SelectedPath;

            Action<string> performOnEachFolder = (s) => this.Invoke(new Action(() => listUpdate2(s)));
            foreach (string emptyFolder in GetAllEmptyFolders(dirPath, performOnEachFolder))
                this.Invoke(new Action(() => listUpdate2(emptyFolder)));

        }
    }

    private static IEnumerable<string> GetAllEmptyFolders(string path, Action<string> performOnEachFolder)
    {

        performOnEachFolder(path);

        EmptyResult result = IsDirectoryEmpty(path);

        if (result == EmptyResult.Empty)
            yield return path;

        if (result == EmptyResult.Error)
            yield break;

        //A reparse point may indicate a recursive file structure. Cause this to stop the recursion. 
        //http://blogs.msdn.com/b/oldnewthing/archive/2004/12/27/332704.aspx
        if ((File.GetAttributes(path) & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
            yield break;

        IEnumerator<string> it = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly).GetEnumerator();

        while (it.MoveNext())
        {
            foreach (string emptyFolder in GetAllEmptyFolders(it.Current, performOnEachFolder))
            {
                yield return emptyFolder;
            }
        }
    }

    private enum EmptyResult
    {
        Empty = 1,
        Used = 2,
        Error = 3
    }

    private static EmptyResult IsDirectoryEmpty(string path)
    {
        try
        {
            return !Directory.EnumerateFileSystemEntries(path).Any() ? EmptyResult.Empty : EmptyResult.Used;
        }
        catch (UnauthorizedAccessException)
        {
            //We do not want the method to throw as that will cause problems with the iterator block.
            return EmptyResult.Error;
        }
    }
user1112560
  • 185
  • 1
  • 8
  • Thanks for this, it worked. However it can't handle long directory paths. –  Oct 01 '14 at 14:24