| Главная | Журнал | Форум | Wiki | DRKB | Страны мира |
Получение списка файлов и директорий в VB 2010ВведениеКак правило разработчики стремятся заставить выполняться программы быстрее и, чтобы при этом они были проще в использовании, но иногда это закрывает одни двери и открывает другие. Как раз это и произошло с Directory.GetFiles и Directory.GetDirectories. Для ускорения получения списков из файловой системы, старые API-методы findfirst и findnext были заменены на GetFiles и GetDirectories. Недостатком GetFiles и GetDirectories было то, что эти методы возвращали массивы и процессу приходилось ждать, пока весь массив не считается. Для устранения ожидания были созданы более продвинутые их аналоги: EnumerateFiles и EnumerateDirectories, которые позволяют рабочему процессу сразу начать работать с файлами, недожидаясь полной загрузки списка, однако и тут есть несколько незначительных препятствий. Используя EnumerateFiles и EnumerateDirectories у вас отпадает необходимость в использовании API функций, в построении собственного рекурсивного кода для обхода всех под-директорий. Ну и как уже упоминалось выше, отпадает необходимость в ожидании получения всего списка, чтобы начать работать с результатами. Основной неприятный момент здесь в том, что если возникнет ошибка при получении списка файлов или директорий, то методы EnumerateXxx сгенерируют исключение и процесс обхода файловой системы будет прерван. Давайте взглянем на EnumerateFiles и EnumerateDirectories, посмотрим как использовать LINQ и обработчики исключений при получении списков файлов и папок. Использование EnumerateFiles и EnumerateDirectoriesВерсии EnumerateFiles и EnumerateDirectories существуют в обоих классах Directory и DirectoryInfo пространства имен System.IO. Версия в классе Directory может проходить и возвращать только подкаталоги. Для работы с файлами или каталогами можно воспользоваться версией в DirectoryInfo. Оба метода EnumerateFiles и EnumerateDirectories имеют несколько перегруженных версий, которые имеют различные аргументы включая начальный путь, маску файлов и аргумент SearchOption позволяющий задать, будет ли осуществляться поиск только в каталогах верхнего уровня или во всех директориях. Следующий код использует вызов Directory.EnumerateFiles, возвращающий список файлов в корневом каталоге диска C:. Метод Array.ForEach преобразует результат поиска в массив и выводит результаты в консоль.
Dim files = From file In Directory.EnumerateFiles("C:\")
Select file
Array.ForEach(files.ToArray(), Sub(f) Console.WriteLine(f))
Это самый простой пример использования EnumerateFiles и EnumerateDirectories - собственно то, чего мы и хотим от фреймворка. Обработка исключений EnumerateDirectoriesЕсли вызвать Directory.EnumerateDirectories с аргументом SearchOption.AllDirectories, то EnumerateDirectories начнёт выполнять обход директории, включая поддиректории. Однако, если начать обход корневого каталога, то есть большая вероятность, что какая-нибудь директория вызовет исключение. Как правило исключения возникают при обходе папок с пользователькими данными. Например, если написать:
Dim d = Directory.EnumerateDirectories("C:\", "*.*", SearchOption.AllDirectories)
Тогда код будет компилироваться и работать. Если же результат источника использовать в for loop:
'Получить все директории
For Each d In Directory.EnumerateDirectories("C:\", "*.*", SearchOption.AllDirectories)
Console.WriteLine(d)
Next
то при обращении к директории C:\Documents and Settings может возникнуть исключение UnauthorizedAccessException. Чтобы поймать исключение
помещаем for loop в блок Try Catch:
Try
For Each d In Directory.EnumerateDirectories("C:\", "*.*", SearchOption.AllDirectories)
Console.WriteLine(d)
Next
Catch ex As Exception
Console.WriteLine("Handle exception here")
End Try
Если понадобиться отловить все возможные исключения, то можно воспользоваться классом Exception или сделать несколько блоков catch, чтобы обработать каждое исключение индивидуально. Тем не менее, чтобы получить все директории, даже если доступ запрещен, то потребуется несколько иной подход, нежели просто использование аргумента SearchOption.AllDirectories. Поиск по всем директориям с обработкой исключенийПредположим, вы хотите найти все папки, а при возникновении исключения пропустить директорию и продолжить. Для этого можно воспользоваться аргументом SearchOption.ContinueOnErrors либо сделать раздельный вызов для каждой поддиректории, с обработчиком событий, чтобы можно было обработать исключительную ситуацию и продолжить обход следующих подпапок. Для эффективного непрерывного обхода директорий можно использовать объект Stack. В процессе извлекая из стека корневые папки и подпапки, обрабатывая исключения и продолжая обработку подпапок, пока все директории не будут пройдены: Imports System.IO Imports System.Security Module Module1 Sub Main() Dim results As List(Of String) = New List(Of String) Dim start As String = "c:\" results.Add(start) Dim stack As Stack(Of String) = New Stack(Of String) Do Try Debug.WriteLine(start) Dim dirs = From d In Directory.EnumerateDirectories(start, "*.*", SearchOption.TopDirectoryOnly) Select d ' многострочное Lambda-выражение - на самом деле здесь не обязательно Array.ForEach(dirs.ToArray(), Sub(d) stack.Push(d) End Sub) start = stack.Pop() results.Add(start) Catch ex As UnauthorizedAccessException Console.WriteLine(ex.Message) start = stack.Pop() results.Add(start) End Try Loop Until (stack.Count = 0) For Each d In results Console.WriteLine(d) Next Console.ReadLine() End Sub End Module Листинг 1: Использование стека для отслеживания директорий верхнего уровня и обработки поддиректорий в случае возникновения исключения. List (Of String) будет содержать найденные каталоги. Переменная start указывает, что поиск производится в корневом каталоге диска C:. stack используется для хранения каталогов, которые необходимо найти. Цикл Do запускает процесс, а Try содержит блок обработки исключений. Выражение Dim dirs запускает поиск подпапок в директории указанной в start. Аргумент SearchOption.TopDirectoryOnly указывает, что искать поддиректории необходимо только в каталоге указанном в start. (параметр "*.*" можно не указывать, если дополнительная фильтрация не требуется) Array.ForEach запихивает все дочерние папки в stack, используя для этого многострочное Lambda-выражение. Далее, из stack извлекается папка и сохранятся в списке результатов. Процесс продолжается, пока стек не станет пустым. При возникновении исключения из стека вновь извлекается значение и добавляется в список результатов. Обход файловой системы начиная с корня - довольно длительный процесс. Но поскольку код разбит на несколько этапов, то у Вас есть много возможностей взаимодействовать с результатами по ходу выполнения данного примера, кроме того можно даже запихнуть этот код в фоновый процесс как, вероятно, это делает Windows Explorer. РезюмеEnumerateFiles и EnumerateDirectories позволяют давольно легко получать информацию о файлах и каталогах. Самая распространенная проблема для разработчиков, это то, что эти методы останавливают свою работу при возникновении исключения. Тем не менее, разделив вызовы для каждой директориии можно управлять исключениями при помощи внешнего цикла. |
Основные разделы сайта
|
|
|