Лучший способ выбрать случайный файл из каталога
Каков наилучший способ выбора случайного файла из каталога в Python?
Изменить: Вот что я делаю:
import os
import random
import dircache
dir = 'some/directory'
filename = random.choice(dircache.listdir(dir))
path = os.path.join(dir, filename)
Это особенно плохо, или есть особенно лучший способ?
Ответы
Ответ 1
import os, random
random.choice(os.listdir("C:\\")) #change dir name to whatever
Относительно вашего отредактированного вопроса: во-первых, я предполагаю, что вы знаете риски использования dircache
, а также тот факт, что он устарел с 2.6, и удален в 3.0.
Во-вторых, я не вижу здесь каких-либо условий гонки. Ваш объект dircache
в основном неизменен (после того, как список каталогов кэшируется, он никогда не читается снова), поэтому никакого вреда в параллельном чтении от него.
Кроме этого, я не понимаю, почему вы видите какие-либо проблемы с этим решением. Это нормально.
Ответ 2
Языковое агностическое решение:
1) Получите общее количество. файлов в указанной директории.
2) Выберите случайное число от 0 до [общее число. файлов - 1].
3) Получите список имен файлов как подходящую индексированную коллекцию или такую.
4) Выберите n-й элемент, где n - случайное число.
Ответ 3
Если вам нужны каталоги, ответ Yuval A. В противном случае:
import os, random
random.choice([x for x in os.listdir("C:\\") if os.path.isfile(os.path.join("C:\\", x))])
Ответ 4
Проблема с большинством представленных решений заключается в том, что вы загружаете весь свой вход в память, что может стать проблемой для больших входов/иерархий. Здесь решение, адаптированное из The Perl Cookbook от Tom Christiansen и Nat Torkington. Чтобы получить произвольный файл в любом месте под каталогом:
#! /usr/bin/env python
import os, random
n=0
random.seed();
for root, dirs, files in os.walk('/tmp/foo'):
for name in files:
n=n+1
if random.uniform(0, n) < 1: rfile=os.path.join(root, name)
print rfile
Обобщение бит делает удобным script:
$ cat /tmp/randy.py
#! /usr/bin/env python
import sys, random
random.seed()
n=1
for line in sys.stdin:
if random.uniform(0, n)<1: rline=line
n=n+1
sys.stdout.write(rline)
$ /tmp/randy.py < /usr/share/dict/words
chrysochlore
$ find /tmp/foo -type f | /tmp/randy.py
/tmp/foo/bar
Ответ 5
Независимо от используемого языка вы можете прочитать все ссылки на файлы в каталоге в datastructure как массив (что-то вроде "listFiles" ), получить длину массива. вычислить случайное число в диапазоне от '0' до 'arrayLength-1' и получить доступ к файлу с определенным индексом. Это должно работать не только в python.
Ответ 6
Если вы не знаете, какие файлы есть, вам нужно будет получить список, а затем просто выберите случайный индекс в списке.
Здесь одна попытка:
import os
import random
def getRandomFile(path):
"""
Returns a random filename, chosen among the files of the given path.
"""
files = os.listdir(path)
index = random.randrange(0, len(files))
return files[index]
РЕДАКТИРОВАТЬ. Сейчас речь идет о страхе перед "состоянием гонки", которое я могу только предположить, это типичная проблема добавления/удаления файлов, когда вы пытаетесь выбрать случайный файл.
Я не верю, что есть способ обойти это, за исключением того, что любая операция ввода-вывода по своей сути является "небезопасной", то есть может быть неудачной. Таким образом, алгоритм для открытия случайно выбранного файла в данном каталоге должен:
- Фактически
open()
выбран файл и обрабатывать сбой, так как файл больше не может быть
- Вероятно, ограничьте себя множеством попыток, поэтому он не умирает, если каталог пуст или ни один из файлов не доступен для чтения.