Извлечение файлов из каталога, содержащего большое количество файлов

У меня есть каталог, содержащий почти 14 000 000 образцов аудио в формате *.wav.

Все свободное хранилище, никаких подкаталогов.

Я хочу перебирать файлы, но когда я использую DirectoryInfo.GetFiles() в этой папке, все приложение замерзает в течение нескольких минут!

Можно ли это сделать другим путем? Возможно, прочитайте 1000, обработайте их, затем возьмите следующие 1000 и так далее?

Ответ 1

Вы пробовали метод EnumerateFiles класса DirectoryInfo?

Как сообщает MSDN

Методы EnumerateFiles и GetFiles отличаются следующим образом: когда вы используйте EnumerateFiles, вы можете начать перечислять коллекцию FileInfo объекты перед возвратом всей коллекции; когда ты используйте GetFiles, вы должны подождать, пока весь массив объектов FileInfo будет прежде чем вы сможете получить доступ к массиву. Поэтому, когда вы работа со многими файлами и каталогами, EnumerateFiles может быть больше эффективным.

Ответ 2

В .NET 4.0 Directory.EnumerateFiles(...) есть IEnumerable<string> (а не string[] of Directory.GetFiles(...)), поэтому он может передавать записи, а не буферизировать их все; то есть.

foreach(var file in Directory.EnumerateFiles(path)) {
    // ...
}

Ответ 3

вы попадаете в ограничение самой файловой системы Windows. Когда количество файлов в каталоге увеличивается до большого числа (а 14M - за пределами этого порога), доступ к каталогу становится невероятно медленным. Неважно, читаете ли вы один файл за раз или 1000, это просто доступ к каталогу.

Один из способов решения этой проблемы - создать подкаталоги и разбить ваши файлы на группы. Если каждый каталог имеет 1000-5000 (угадывание, но вы можете поэкспериментировать с реальными числами), вы должны получить приличную производительность при открытии/создании/удалении файлов.

Вот почему, если вы посмотрите на такие приложения, как Doxygen, который создает файл для каждого класса, они следуют этой схеме и помещают все в 2 уровня подкаталогов, которые используют случайные имена.

Ответ 4

Используйте Win32 Api FindFile, чтобы сделать это, не блокируя приложение.

Вы также можете вызвать Directory.GetFiles в System.Threading.Task (TPL), чтобы предотвратить зависание вашего пользовательского интерфейса.

Ответ 5

Enjoy.

    public List<string> LoadPathToAllFiles(string pathToFolder, int numberOfFilesToReturn)
    {
        var DirInfo = new DirectoryInfo(pathToFolder);
        var firstFiles = DirInfo.EnumerateFiles().Take(numberOfFilesToReturn).ToList();
        return firstFiles.Select(l => l.FullName).ToList();
    }

Ответ 6

Я часто сталкиваюсь с этой проблемой при обращении к большим файлам в одном каталоге. Подкаталоги - хороший вариант, но вскоре даже иногда они не предлагают много помощи. Теперь я создаю файл индекса - текстовый файл с именами всех файлов в каталоге (при создании файлов в этом каталоге). Затем я читаю индексный файл, а затем открываю фактический файл из каталога для обработки