C# - File Enumerator

Example/Tutorials

This tutorial helps demonstrate a built-in File Enumerator.

Looking At Directory Enumerator

The starting place is to read the DirectoryEnumerator guide. Once familiarized you can see what we changed here to make it work.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace DirectoryTestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            MainAsync(args).GetAwaiter().GetResult();
        }

        static async Task MainAsync(string[] args)
        {
            string rootFolder = "C:\\";
            await DirectoryTestAsync(rootFolder);
            await Console.In.ReadLineAsync();
        }

        static async Task DirectoryTestAsync(string rootFolder)
        {
            await Console.Out.WriteLineAsync($"Enumerate Directories Test Begins.");
            var seconds = 0.0;
            var limit = 5;
            for (int i = 0; i < limit; i++)
            {
                seconds += await EnumerateDirectoriesAsync(rootFolder, i);
            }
            await Console.Out.WriteLineAsync(
                $"Enumerate Directories Test Complete.\n\tTotal Time: {seconds}s\tAvg. Time: {seconds / limit}s\n");
        }

        static async Task<double> EnumerateDirectoriesAsync(string rootFolder, int iteration)
        {
            var t = await Task.Run( async () =>
            {
                await Console.Out.WriteLineAsync($"\tTest {iteration}: Finding Directories in ({rootFolder}) Begins...");
                Stopwatch sw = Stopwatch.StartNew();

                var dirs = new List<string>();
                dirs = EnumerateDirectories(rootFolder, "*", SearchOption.AllDirectories).ToList();
                sw.Stop();
                var seconds = sw.ElapsedMilliseconds / 1000.0;

                await Console.Out.WriteLineAsync($"\t\t== Test {iteration} Summary ==");
                await Console.Out.WriteLineAsync($"\t\t   Directories Enumerated: {dirs.Count}");
                await Console.Out.WriteLineAsync($"\t\t   Elapsed Time: {seconds}s");

                return seconds;
            });

            return t;
        }

        public static IEnumerable<string> EnumerateDirectories(string parentDirectory, string searchPattern,
                                                               SearchOption searchOpt)
        {
            var result = Enumerable.Empty<string>();
            try
            {
                var directories = Enumerable.Empty<string>();
                if (searchOpt == SearchOption.AllDirectories)
                {
                    directories = Directory.EnumerateDirectories(parentDirectory)
                                            .SelectMany(x => EnumerateDirectories(x, searchPattern, searchOpt));
                }
                result = directories.Concat(Directory.EnumerateDirectories(parentDirectory, searchPattern));
            }
            catch (UnauthorizedAccessException) { }

            return result;
        }
    }
}

The Steps

The logic behind this is pretty light/easy to get behind. In every folder, I need all the filepathnames. So lets convert EnumerateDirectories into EnumerateFiles.

        public static IEnumerable<string> EnumerateFiles(string parentDirectory, string searchPattern,
                                                               SearchOption searchOpt)
        {
            var result = Enumerable.Empty<string>();
            try
            {
                var directories = Enumerable.Empty<string>();
                if (searchOpt == SearchOption.AllDirectories)
                {
                    directories = Directory.EnumerateDirectories(parentDirectory)
                                            .SelectMany(x => EnumerateFiles(x, searchPattern, searchOpt));
                }
                result = directories.Concat(Directory.EnumerateFiles(parentDirectory, searchPattern));
            }
            catch (UnauthorizedAccessException) { }

            return result;
        }

The main difference here is on the result returned. The other changes are superficial. First we have to know the folders, then we recursively get all the files out of the folder once we start returning up the stack.

All The Changes To Make It Work

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FileTestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            MainAsync(args).GetAwaiter().GetResult();
        }

        static async Task MainAsync(string[] args)
        {
            string rootFolder = "C:\\";
            await FileTestAsync(rootFolder);
            await Console.In.ReadLineAsync();
        }

        static async Task FileTestAsync(string rootFolder)
        {
            await Console.Out.WriteLineAsync($"Enumerate Files Test Begins.");
            var seconds = 0.0;
            var limit = 5;
            for (int i = 0; i < limit; i++)
            {
                seconds += await EnumerateFilesAsync(rootFolder, i);
            }
            await Console.Out.WriteLineAsync($"Enumerate Files Test Complete.\n\tTotal Time: {seconds}s\tAvg. Time: {seconds / limit}s\n");
        }

        static async Task<double> EnumerateFilesAsync(string rootFolder, int iteration)
        {
            var t = await Task.Run( async () =>
            {
                await Console.Out.WriteLineAsync($"\tTest {iteration}: Finding Files in ({rootFolder}) Begins...");
                Stopwatch sw = Stopwatch.StartNew();

                var dirs = new List<string>();
                dirs = EnumerateFiles(rootFolder, "*", SearchOption.AllDirectories).ToList();
                sw.Stop();
                var seconds = sw.ElapsedMilliseconds / 1000.0;

                await Console.Out.WriteLineAsync($"\t\t== Test {iteration} Summary ==");
                await Console.Out.WriteLineAsync($"\t\t   Files Found: {dirs.Count}");
                await Console.Out.WriteLineAsync($"\t\t   Elapsed Time: {seconds}s");

                return seconds;
            });

            return t;
        }

        public static IEnumerable<string> EnumerateFiles(string parentDirectory, string searchPattern,
                                                               SearchOption searchOpt)
        {
            var result = Enumerable.Empty<string>();
            try
            {
                var directories = Enumerable.Empty<string>();
                if (searchOpt == SearchOption.AllDirectories)
                {
                    directories = Directory.EnumerateDirectories(parentDirectory)
                                            .SelectMany(x => EnumerateFiles(x, searchPattern, searchOpt));
                }
                result = directories.Concat(Directory.EnumerateDirectories(parentDirectory, searchPattern));
            }
            catch (UnauthorizedAccessException) { }

            return result;
        }
    }
}

Sources