Во-первых, прости мой плохой английский; о)
У меня возникла проблема, которая привела меня на эту страницу: перечислить файлы каталога и его подкаталогов, не блокируя исключение UnauthorizedAccessException, и, подобно новому методу .Net 4 DirectoryInfo.Enumerate ..., получить первый результат до конца весь запрос.
С помощью различных примеров, найденных здесь и там в Интернете, я наконец-то напишу этот метод:
public static IEnumerable<FileInfo> EnumerateFiles_Recursive(this DirectoryInfo directory, string searchPattern, SearchOption searchOption, Func<DirectoryInfo, Exception, bool> handleExceptionAccess)
{
Queue<DirectoryInfo> subDirectories = new Queue<DirectoryInfo>();
IEnumerable<FileSystemInfo> entries = null;
// Try to get an enumerator on fileSystemInfos of directory
try
{
entries = directory.EnumerateFileSystemInfos(searchPattern, SearchOption.TopDirectoryOnly);
}
catch (Exception e)
{
// If there's a callback delegate and this delegate return true, we don't throw the exception
if (handleExceptionAccess == null || !handleExceptionAccess(directory, e))
throw;
// If the exception wasn't throw, we make entries reference an empty collection
entries = EmptyFileSystemInfos;
}
// Yield return file entries of the directory and enqueue the subdirectories
foreach (FileSystemInfo entrie in entries)
{
if (entrie is FileInfo)
yield return (FileInfo)entrie;
else if (entrie is DirectoryInfo)
subDirectories.Enqueue((DirectoryInfo)entrie);
}
// If recursive search, we make recursive call on the method to yield return entries of the subdirectories.
if (searchOption == SearchOption.AllDirectories)
{
DirectoryInfo subDir = null;
while (subDirectories.Count > 0)
{
subDir = subDirectories.Dequeue();
foreach (FileInfo file in subDir.EnumerateFiles_Recursive(searchPattern, searchOption, handleExceptionAccess))
{
yield return file;
}
}
}
else
subDirectories.Clear();
}
Я использую очередь и рекурсивный метод для поддержания традиционного порядка (содержимое каталога, а затем содержимое первого подкаталога и его собственных подкаталогов, а затем содержимое второго ...). Параметр handleExceptionAccess - это просто вызов функции, когда исключение выдается с каталогом; функция должна возвращать true, чтобы указать, что исключение следует игнорировать.
С помощью этого метода вы можете написать:
DirectoryInfo dir = new DirectoryInfo("c:\\temp");
long size = dir.EnumerateFiles_Recursive("*", SearchOption.AllDirectories, (d, ex) => true).Sum(f => f.Length);
И вот мы здесь: все исключения при попытке перечислить каталог будут игнорироваться!
Надеюсь, что эта помощь
Lionel
PS: по причине, которую я не могу объяснить, мой метод более быстрый, чем один из фреймворков 4 ...
PPS: вы можете получить мои тестовые решения с источником для этих методов: здесь TestDirEnumerate . Я пишу EnumerateFiles_Recursive, EnumerateFiles_NonRecursive (используйте очередь, чтобы избежать рекурсии) и EnumerateFiles_NonRecursive_TraditionalOrder (используйте стек очереди, чтобы избежать рекурсии и поддерживать традиционный порядок). Хранить эти 3 метода неинтересно, я пишу их только для проверки лучшего. Я думаю, чтобы сохранить только последний.
Я также написал эквивалент для EnumerateFileSystemInfos и EnumerateDirectories.