Подтвердить что ты не робот

Лучший способ выбрать случайный файл из каталога

Каков наилучший способ выбора случайного файла из каталога в Python?

Изменить: Вот что я делаю:

import os
import random
import dircache

dir = 'some/directory'
filename = random.choice(dircache.listdir(dir))
path = os.path.join(dir, filename)

Это особенно плохо, или есть особенно лучший способ?

4b9b3361

Ответ 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() выбран файл и обрабатывать сбой, так как файл больше не может быть
  • Вероятно, ограничьте себя множеством попыток, поэтому он не умирает, если каталог пуст или ни один из файлов не доступен для чтения.