Быстрый (низкоуровневый) метод для рекурсивной обработки файлов в папках - PullRequest
4 голосов
/ 18 января 2010

Мое приложение индексирует содержимое всех жестких дисков на компьютерах конечных пользователей. Я использую Directory.GetFiles и Directory.GetDirectories для рекурсивной обработки всей структуры папок. Я индексирую только несколько выбранных типов файлов (до 10 типов файлов).

Я вижу в профилировщике, что большая часть времени индексации тратится на перечисление файлов и папок - в зависимости от соотношения файлов, которые фактически будут проиндексированы до 90 процентов времени.

Я бы хотел сделать индексацию максимально быстрой. Я уже оптимизировал само индексирование и обработку проиндексированных файлов.

Я думал об использовании вызовов Win32 API, но на самом деле я вижу в профилировщике, что большая часть времени обработки фактически тратится на эти вызовы API, выполняемые .NET.

Существует ли (возможно, низкоуровневый) метод, доступный из C #, который бы делал перечисление файлов / папок хотя бы частично быстрее?


Как и просили в комментарии, мой текущий код (просто схема с обрезанными нерелевантными частями):

    private IEnumerable<IndexedEntity> RecurseFolder(string indexedFolder)
    {
        //for a single extension:
        string[] files = Directory.GetFiles(indexedFolder, extensionFilter);
        foreach (string file in files)
        {
            yield return ProcessFile(file);
        }
        foreach (string directory in Directory.GetDirectories(indexedFolder))
        {
            //recursively process all subdirectories
            foreach (var ie in RecurseFolder(directory))
            {
                yield return ie;
            }
        }
    }

Ответы [ 2 ]

2 голосов
/ 18 января 2010

В .NET 4.0 есть встроенные перечисляемые методы перечисления файлов ; так как это не далеко, я бы попробовал использовать это. Это может быть, в частности, одним из факторов, если у вас есть какие-либо папки, которые массово заполнены (требующие большого массива).

Если глубина - это проблема, я бы рассмотрел возможность использования вашего метода для использования локального стека / очереди и одного блока итератора. Это уменьшит путь к коду, используемому для перечисления глубоких папок:

    private static IEnumerable<string> WalkFiles(string path, string filter)
    {
        var pending = new Queue<string>();
        pending.Enqueue(path);
        string[] tmp;
        while (pending.Count > 0)
        {
            path = pending.Dequeue();
            tmp = Directory.GetFiles(path, filter);
            for(int i = 0 ; i < tmp.Length ; i++) {
                yield return tmp[i];
            }
            tmp = Directory.GetDirectories(path);
            for (int i = 0; i < tmp.Length; i++) {
                pending.Enqueue(tmp[i]);
            }
        }
    }

Итерируйте это, создавая ProcessFile s из результатов.

1 голос
/ 18 января 2010

Если вы считаете, что реализация .NET вызывает проблему, тогда я предлагаю использовать вызовы winapi _findfirst, _findnext и т. Д.

Мне кажется, что .NET требует много памяти, потому чтосписки полностью копируются в массивы на каждом уровне каталога - поэтому, если ваша структура каталогов имеет глубину 10 уровней, у вас есть 10 версий файлов массива в любой момент времени и выделение / освобождение этого массива для каждого каталога в структуре.

Использование одного и того же рекурсивного метода с _findfirst и т. Д. Требует только того, чтобы дескрипторы позиции в структуре каталогов сохранялись на каждом уровне рекурсии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...