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