Содержание
Необходимо вывести список всех файлов, расположенных в определенной папке, включая файлы, которые находятся в подпапках. Это одна из типовых задач в программировании и решений этой задачи, как и любой другой, есть несколько. Наиболее простым является решение с использованием уже готовых методов класса DirectoryInfo
. Однако, такой подход не всегда приводит к желаемому результату, например, в том случае, если доступ к определенному каталогу запрещен для текущего пользователя. В этом случае нам приходится реализовывать свой собственный алгоритм обхода дерева каталогов в C#.
Задача
Под фразой «обход дерева каталогов», в первую очередь, подразумевается получение доступа к каждому файлу в каждом вложенном подкаталоге в заданной корневой папке на любую глубину. Глубина может быть задана пользователем или не задаваться. При этом, совсем необязательно открывать каждый файл — можно извлечь имя файла или подпапки в виде string
или же получить информацию об объекте с использованием классов FileInfo или DirectoryInfo.
При обходе дерева каталогов могут использоваться алгоритмы с использованием рекурсии или без использования рекурсии. Сегодня мы рассмотрим пример обхода дерева каталогов в C# с использованием рекурсии.
Алгоритм обхода дерева каталогов с использованием рекурсии
Как было сказано выше, рекурсия — это вызов методом самого себя. Чтобы реализовать обход дерева папок в C# с использованием рекурсии необходимо выполнить следующие действия:
- Просматриваем все файлы в заданной папке;
- Получаем все подкаталоги в текущей папке;
- В цикле проходим по каждому полученному подкаталогу и считываем все файлы:
- текущим становится очередной просматриваемый каталог
- считываем все файлы
- возвращаемся на п.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# с использованием рекурсии. Рекурсия позволяет сделать ваш код элегантнее и короче, однако, следует помнить, что рекурсивные методы стоит использовать с осторожностью, так как неверно реализованный алгоритм может привести к ошибкам переполнения стека и, в лучшем случае, к аварийному завершению работы вашей программы.