Thursday, October 20, 2005

Breadth-first directory traversal without recursion


Update 2011-05-01: This should probably be rewritten to use the new IEnumerable-returning directory listing method.

public const uint DefaultMaxDirectoryDepth = 32;

public delegate void DirectoryVisitedDelegate(string path, IFileSystem fileSystem);

public static void Traverse
(
    string rootPath,
    DirectoryVisitedDelegate visitedDelegate,
    IFileSystem fileSystem
)
{
    Traverse(rootPath, visitedDelegate, fileSystem, DefaultMaxDirectoryDepth);
}

public static void Traverse
(
    string rootPath,
    DirectoryVisitedDelegate visitedDelegate,
    IFileSystem fileSystem,
    uint maxDepth
)
{
    char[] directorySplitChars = new char[] { Path.DirectorySeparatorChar };
    Queue<string> directoryQueue = new Queue<string>();

    directoryQueue.Enqueue(rootPath);

    while (directoryQueue.Count > 0)
    {
        string path = directoryQueue.Dequeue();

        try
        {
            foreach (string subDirectoryPath in fileSystem.GetDirectories(path))
            {
                if (subDirectoryPath.Split(directorySplitChars).Length < maxDepth)
                {
                    directoryQueue.Enqueue(subDirectoryPath);
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            // We can't look in that directory. Never mind.
        }
        catch (FileNotFoundException)
        {
            // The directory has gone away. Never mind.
        }

        visitedDelegate.Invoke(path, fileSystem);
    }
}