Эффективно случайное перечисление файлов из огромного каталога
Я хочу иметь возможность рекурсивно перечислять файлы с определенным шаблоном поиска (например, *.txt) из каталога. Но с парой ограничений:
- Механизм должен быть очень эффективным. Цель состоит в том, чтобы перечислить файл один за другим (используя IEnumerable), чтобы при наличии огромного списка файлов не потребовалось бы много времени, чтобы получить один файл для обработки.
- Перечисление должно возвращать файлы случайным образом, так что, если два экземпляра моей программы пытаются перечислить каталог, оба не должны видеть файлы в одной и той же последовательности.
Учитывая требования, DirectoryInfo.EnumerateFiles выглядит многообещающе, за исключением того, что оно не удовлетворяет второму требованию. Если я уберу оценку производительности, решение будет простым (просто получите всю коллекцию и рандомизируйте последовательность перед доступом).
Может кто-нибудь предложить возможные варианты реализации C# в.net 3.5/4.0?
1 ответ
То, что вы просите, невозможно.
Действительно "случайное" перечисление (в том смысле, что порядок, вероятно, меняется каждый раз), требует стратегии "выбор без замены". Такая стратегия обязательно требует двух пулов: один из "выбранных" файлов и один из "не выбранных". Список "unchosen" должен быть заполнен прежде, чем что-либо из него может быть "выбрано" случайным образом. Это нарушает ваше требование № 1.
Две мысли о том, как решить вашу проблему:
В чем проблема, когда два экземпляра видят файлы в одном и том же порядке? Если это проблема блокировки файла, выберите блокировку только для чтения.
Вы могли бы быть в состоянии избежать неприятностей с подходом "удерживающей груды". Здесь вы должны создать свой собственный класс перечислителя, который начинается с чтения небольшого количества записей FileInfo в коллекцию "Hold". Затем, каждый раз, когда ваш вызывающий код запрашивает файл, он либо передает его непосредственно из EnumerateFiles, либо читает его оттуда, но заменяет его на один из вашей стопки "Hold" и возвращает его вместо этого. Решение будет случайным, пока EnumerateFiles ничего не вернет, и в этот момент вы очистите стопку Hold. Это не обеспечит действительно случайный порядок выбора, но, возможно, это добавит нечеткости в заказ, чтобы удовлетворить ваши потребности. Максимальный размер коллекции "Hold" можно настроить по вкусу, чтобы сбалансировать вашу потребность в "случайности" и необходимость быстрого получения первого файла.