Алгоритм обхода дерева каталогов в C# с использованием рекурсии

Необходимо вывести список всех файлов, расположенных в определенной папке, включая файлы, которые находятся в подпапках. Это одна из типовых задач в программировании и решений этой задачи, как и любой другой, есть несколько. Наиболее простым является решение с использованием уже готовых методов класса DirectoryInfo. Однако, такой подход не всегда приводит к желаемому результату, например, в том случае, если доступ к определенному каталогу запрещен для текущего пользователя. В этом случае нам приходится реализовывать свой собственный алгоритм обхода дерева каталогов в C#.

Задача

Под фразой «обход дерева каталогов», в первую очередь, подразумевается получение доступа к каждому файлу в каждом вложенном подкаталоге в заданной корневой папке на любую глубину. Глубина может быть задана пользователем или не задаваться. При этом, совсем необязательно открывать каждый файл — можно извлечь имя файла или подпапки в виде string или же получить информацию об объекте с использованием классов FileInfo или DirectoryInfo.

При обходе дерева каталогов могут использоваться алгоритмы с использованием рекурсии или без использования рекурсии. Сегодня мы рассмотрим пример обхода дерева каталогов в C# с использованием рекурсии.

Алгоритм обхода дерева каталогов с использованием рекурсии

Как было сказано выше, рекурсия — это вызов методом самого себя. Чтобы реализовать обход дерева папок в C# с использованием рекурсии необходимо выполнить следующие действия:

  1. Просматриваем все файлы в заданной папке;
  2. Получаем все подкаталоги в текущей папке;
  3. В цикле проходим по каждому полученному подкаталогу и считываем все файлы:
    1. текущим становится очередной просматриваемый каталог
    2.  считываем все файлы
  4. возвращаемся на п.3

Реализация алгоритма обхода дерева каталогов в C# с использованием рекурсии

Вначале реализуем рекурсивный метод с помощью которого мы будем обходить дерево каталогов:

static StringCollection log = new StringCollection();
static void Walk(DirectoryInfo root)
{
    FileInfo[] files = null;
    DirectoryInfo[] subDirs = null;

    // Получаем все файлы в текущем каталоге
    try
    {
        files = root.GetFiles("*.*");
    }
    catch (UnauthorizedAccessException e)
    {
        log.Add(e.Message);
    }
    catch (DirectoryNotFoundException e)
    {
        Console.WriteLine(e.Message);
    }

    if (files != null)
    {
        //выводим имена файлов в консоль
        foreach (FileInfo fi in files)
        {
            Console.WriteLine(fi.FullName);
        }
        //получаем все подкаталоги
        subDirs = root.GetDirectories();
        //проходим по каждому подкаталогу
        foreach (DirectoryInfo dirInfo in subDirs)
        {
            //РЕКУРСИЯ
            Walk(dirInfo);
        }
    }
}

В приведенном выше коде мы обрабатываем два возможных исключения при чтении списка файлов — это UnauthorizedAccessException и DirectoryNotFoundException. О том, что такое исключения и как их фильтровать смотри здесь и здесь. UnauthorizedAccessException  возникает, когда у пользователя недостаточно привилегий для доступа к файлу или папке, а DirectoryNotFoundException — когда заданная папка не найдена по указанному пути. Обработка исключений позволяет нам избежать аварийного завершения программы и продолжить выполнение кода. Отдельно в коде отмечено место рекурсивного вызова метода Walk().

Таким образом, метод Walk() будет вызывать сам себя до тех пор, пока не будут прочитаны все файлы во всех поддиректориях по указанному пути.

Исходный код программы рекурсивного обхода дерева каталогов в C#

Ниже представлен полный исходник программы рекурсивного обхода дерева каталогов в C#:

using System;
using System.IO;
using System.Collections.Specialized;

namespace FileSystem
{
    class Program
    {
        static StringCollection log = new StringCollection();

        static void Main(string[] args)
        {
            //задаем папку для обхода
            string rootDir = @"c:\CSharp Output\";
            //вызываем рекурсивный метод
            Walk(new DirectoryInfo(rootDir));
            Console.WriteLine("Файлы, доступ к которым запрещен:");
            foreach (string s in log)
            {
                Console.WriteLine(s);
            }
        }

        static void Walk(DirectoryInfo root)
        {
            FileInfo[] files = null;
            DirectoryInfo[] subDirs = null;

            // Получаем все файлы в текущем каталоге
            try
            {
                files = root.GetFiles("*.*");
            }
            catch (UnauthorizedAccessException e)
            {
                log.Add(e.Message);
            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
            }

            if (files != null)
            {
                //выводим имена файлов в консоль
                foreach (FileInfo fi in files)
                {
                    Console.WriteLine(fi.FullName);
                }
                //получаем все подкаталоги
                subDirs = root.GetDirectories();
                //проходим по каждому подкаталогу
                foreach (DirectoryInfo dirInfo in subDirs)
                {
                    //РЕКУРСИЯ
                    Walk(dirInfo);
                }
            }
        }

    }
}

Итого

Сегодня мы рассмотрели один из возможных и наиболее часто используемых алгоритмов обхода дерева каталогов в C# с использованием рекурсии. Рекурсия позволяет сделать ваш код элегантнее и короче, однако, следует помнить, что рекурсивные методы стоит использовать с осторожностью, так как неверно реализованный алгоритм может привести к ошибкам переполнения стека и, в лучшем случае, к аварийному завершению работы вашей программы.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии