Страницы

Поиск по вопросам

суббота, 8 февраля 2020 г.

DirectoryInfo.EnumerateFiles => Исключение

#c_sharp #net


Нужно получить все файлы по заданной маске. Метод EnumerateFiles выдает исключение,
если какой-то файл имеет системные права доступа. Как это обойти?

var sourceDir = new DirectoryInfo(path);
foreach (var f in sourceDir.EnumerateFiles("*.txt", SearchOption.AllDirectories))
{
     var lvItem = new ListViewItem(Path.GetFileName(f.FullName), 0);
     lvItem.SubItems.Add(Path.GetDirectoryName(f.FullName));
     var fileInfo = new FileInfo(f.FullName);
     lvItem.SubItems.Add(fileInfo.Length + " байт");
     lvItem.SubItems.Add(Directory.GetLastWriteTime(f.FullName).ToShortDateString());
     uiContext.Send(d => listView1.Items.Add(lvItem), null);
}

    


Ответы

Ответ 1



Судя по всему, ничего лучше ручной рекурсии с отловом исключений нет. Можно попробовать так: static IEnumerable EnumerateFilesDeepIgnoringAccessException( DirectoryInfo root, string mask) { var localResult = new List(); try { localResult = root.EnumerateFiles(mask).ToList(); } catch (UnauthorizedAccessException) { // ignore it yield break; } foreach (var fi in localResult) yield return fi; foreach (var di in root.EnumerateDirectories()) { foreach (var fi in EnumerateFilesDeepIgnoringAccessException(di, mask)) yield return fi; } } Код основан на официальном примере, модифицирован для ленивого обхода. Можно ещё избавиться от рекурсии стандартным путём — добавить явную очередь каталогов для обхода. Однако не думаю, что это даст существенный выигрыш по скорости по сравнению с обходом файловой системы. Специфически для вашего кода, я не стал бы заниматься обходом файловой системы в том же потоке, в котором бежит UI — иначе зависаний не избежать. Вам стоит подумать об обходе в отдельном потоке.

Ответ 2



using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; public sealed class FileSystemEnumerable : IEnumerable { private readonly DirectoryInfo _root; private readonly IList _patterns; private readonly SearchOption _option; public FileSystemEnumerable(DirectoryInfo root, string pattern, SearchOption option) { _root = root; _patterns = new List { pattern }; _option = option; } public FileSystemEnumerable(DirectoryInfo root, IList patterns, SearchOption option) { _root = root; _patterns = patterns; _option = option; } public IEnumerator GetEnumerator() { if (_root == null || !_root.Exists) yield break; IEnumerable matches = new List(); try { foreach (var pattern in _patterns) { matches = matches.Concat(_root.EnumerateDirectories(pattern, SearchOption.TopDirectoryOnly)) .Concat(_root.EnumerateFiles(pattern, SearchOption.TopDirectoryOnly)); } } catch (UnauthorizedAccessException) { yield break; } catch (PathTooLongException ptle) { yield break; } catch (System.IO.IOException e) { yield break; } foreach (var file in matches) { yield return file; } if (_option == SearchOption.AllDirectories) { foreach (var dir in _root.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)) { var fileSystemInfos = new FileSystemEnumerable(dir, _patterns, _option); foreach (var match in fileSystemInfos) { yield return match; } } } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } Использование: var root = new DirectoryInfo(path); var searchPattern = @"*.txt"; var searchOption = SearchOption.AllDirectories; var enumerable = new FileSystemEnumerable(root, searchPattern, searchOption);

Комментариев нет:

Отправить комментарий