Preface

The following requires .NET Core 5, a willingness to work with delegates/events, working with classes and asynchronous programming.

At one point in all developer’s career there is a need to traverse folders for sub-folders and files.

Challenges include but not limited to responsive design, keeping a user interface alive while traversing folders and/or files and inaccessible folders from lack of permissions.

Code samples have been kept basic rather than full-fledged for ease of learning.

In some cases it will not be apparent why for instance a method does not assert for accessibility to protected folders. This is because when using methods like Directory.EnumerateFiles the default is to ignore access denied resulting in UnauthorizedAccessException or SecurityException exceptions.

Unorthodox methods known as globbing are presented in the code samples.

In the following example we want to find all .cs files under a folder and all sub-folders but exclude .cs files with Assembly or Designer in their name.

Note supporting classes are in the GitHub repository.

Code:
public static async Task Asynchronous(string parentFolder, string[] patterns, string[] excludePatterns)
{

    List<FileMatchItem> list = new();

    Matcher matcher = new();
    matcher.AddIncludePatterns(patterns);
    matcher.AddExcludePatterns(excludePatterns);

    await Task.Run( () =>
    {
        
        foreach (string file in matcher.GetResultsInFullPath(parentFolder))
        {
            TraverseFileMatch?.Invoke(new FileMatchItem(file));
        }
    });

    Done?.Invoke("Finished");

}
Form code (adapts to WPF)


Code:
using System;
using System.IO;
using System.Windows.Forms;
using DirectoryHelpersLibrary.Classes;
using DirectoryHelpersLibrary.Models;
using WindowsFormsLibrary.Classes;
using WindowsFormsLibrary.LanguageExtensions;

namespace GlobbingProject
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            GlobbingOperations.TraverseFileMatch += TraverseFileMatch;
            GlobbingOperations.Done += Done;
        }

        private void Done(string message)
        {
            Dialogs.AutoCloseDialog(this, message, Properties.Resources.blueInformation_32, 1);
        }

        private void TraverseFileMatch(FileMatchItem sender)
        {
            ResultListBox.InvokeIfRequired(listBox =>
            {
                listBox.Items.Add(Path.Combine(sender.Folder, sender.FileName));
                listBox.SelectedIndex = listBox.Items.Count - 1;
            });
        }

        /// <summary>
        /// Provides what to find via include array and what to exclude
        /// using the exclude array
        /// </summary>
        private async void ExecuteButton_Click(object sender, EventArgs e)
        {
            ResultListBox.Items.Clear();
            string path = DirectoryHelper.SolutionFolder();

            string[] include = { "**/*.cs" };
            string[] exclude = { "**/*Assembly*.cs", "**/*Designer*.cs" };

            await GlobbingOperations.Asynchronous(path, include, exclude);
        }
    }
}
In the project DirectoryHelpersLibrary there are various permutations and overloads for working with folders and files both synchronously and synchronously.


Take time to read this file for high level details.

In the following project, there are two forms, try out both by changing the startup form in Program.cs

GitHub repository

Either clone in Visual Studio or clone using GitHub desktop

https://github.com/karenpayneoregon/...-folders-files