Выбор случайного файла из каталога (с большим количеством файлов) в Python - PullRequest
11 голосов
/ 14 июля 2010

У меня есть каталог с большим количеством файлов (~ 1 мил). Мне нужно выбрать случайный файл из этого каталога. Поскольку файлов так много, os.listdir, естественно, требуется целая вечность.

Есть ли способ, которым я могу обойти эту проблему? Может быть, как-то узнать количество файлов в каталоге (не перечисляя его) и выбрать n-й файл, где n генерируется случайным образом?

Файлы в каталоге имеют произвольные имена.

Ответы [ 5 ]

3 голосов
/ 15 июля 2010

Увы, я не думаю, что есть решение вашей проблемы.Во-первых, я не знаю переносимого API, которое будет возвращать вам количество записей в каталоге (без их перечисления в первую очередь).Во-вторых, я не думаю, что есть API, который бы возвращал вам запись каталога по номеру, а не по имени.

Таким образом, в целом, программе придется перечислять O (n) записей каталога, чтобы получить один случайный элемент.Тривиальный подход для определения количества записей и последующего выбора одного из них либо потребует достаточно ОЗУ для хранения полного списка (os.listdir()), либо потребуется второй раз перечислять каталог, чтобы найти случайный (n) элемент - всего n+n/2 операций.в среднем.

Есть немного лучший подход - но только немного - см. Случайный выбор строк из файлов .Короче говоря, есть способ выбрать случайный элемент из списка / итератора с неизвестной длиной, одновременно читая по одному элементу, и убедиться, что любой элемент может быть выбран с равной вероятностью.Но это не поможет с os.listdir(), потому что он уже возвращает list в памяти, которая уже содержит все записи 1M + - так что вы также можете задать вопрос о len() ...

1 голос
/ 04 ноября 2012

У меня схожая потребность с ОП.

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

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

Код для умного чтения случайной строки из файла в Python, автор Джонатан Купферман:

http://www.regexprn.com/2008/11/read-random-line-in-large-file-in.html

1 голос
/ 14 июля 2010

Я не уверен, что это даже возможно.Даже на уровне VFS или файловой системы нет гарантии того, что количество записей в каталоге даже поддерживается.Например, многие файловые системы просто записывают объединенный размер байта структур записей каталога, содержащихся в данном каталоге.

Оценка может быть сделана, если записи каталога являются структурами фиксированного размера, но сейчас это не является редкостью (рассмотрим LFN для FAT32),Даже если заданная файловая система предоставила счетчик записей без необходимости перебирать каталог, или если VFS кэшировала запись длины каталога, это определенно будет зависеть от операционной системы, файловой системы и ядра.

0 голосов
/ 14 июля 2010

попробуйте, (здесь очень быстро с 50K файлами ...)

import glob
import random

list = glob.glob("*/*.*")
print list[random.randrange(0,list.__len__())]
0 голосов
/ 14 июля 2010

Вы можете запустить это:

http://mail.python.org/pipermail/python-list/2009-July/1213182.html

И это, вероятно, лучшее из возможных решений вашей проблемы, но только там, где n мало - если n становится большим, тогда os.listdir, вероятно, так же хорош для ваших целей.

Я искал и не нашел другого способа открыть файл в каталоге. Если бы у меня было больше времени, я бы немного поигрался и сгенерировал свои собственные ~ 1 млн файлов.


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

Конечно, если файлы в каталоге имеют произвольные имена, вы можете переименовать файлы (?) И поместить их в структуру каталогов, как рекомендует AdamK.

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