2009-03-31 19 views
16

¿Cuál es la mejor manera de elegir un archivo aleatorio de un directorio en Python?La mejor manera de elegir un archivo aleatorio de un directorio

Editar: Aquí es lo que estoy haciendo:

import os 
import random 
import dircache 

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

¿Es esta particularmente malo, o hay una manera particularmente mejor?

+0

Lo siento chicos, presenté accidentalmente antes de que terminara de entrar en mi pregunta. No debería cambiar mucho sin embargo. – JasonSmith

+0

¿Podría aclarar el problema de la condición de carrera? Supongo que te refieres a seleccionar y abrir un archivo sin una ventana intermedia (cuando alguien podría eliminarlo entre elegir e intentar abrirlo, por ejemplo), pero valdría la pena indicarlo explícitamente (suponiendo que te estoy interpretando correctamente).) – Brian

+0

¿Es la condición de carrera porque varios procesos lo harán al mismo tiempo? ¿O la condición de carrera ocurrirá porque hay un escritor que crea archivos y este lector que los está seleccionando? –

Respuesta

39
import os, random 
random.choice(os.listdir("C:\\")) #change dir name to whatever 

cuanto a su pregunta Editado: en primer lugar, que una Supongamos que conoce los riesgos de usar un dircache, así como el hecho de que es deprecated since 2.6, and removed in 3.0.

En segundo lugar, no veo dónde existe ninguna condición de carrera aquí. Su objeto dircache es básicamente inmutable (una vez que la lista de directorios está almacenada en la memoria caché, nunca se vuelve a leer), por lo que no se dañarán las lecturas concurrentes.

Aparte de eso, no entiendo por qué ve algún problema con esta solución. Está bien.

+1

Gracias por mencionar que dircache está en desuso. –

1

Independientemente del idioma utilizado, puede leer todas las referencias a los archivos en un directorio en una estructura de datos como una matriz (algo así como 'listFiles'), obtener la longitud de la matriz. calcule un número aleatorio en el rango de '0' a 'arrayLength-1' y acceda al archivo en el índice determinado. Esto debería funcionar, no solo en Python.

1

Si no sabe de antemano qué archivos hay, tendrá que obtener una lista, luego simplemente elija un índice al azar en la lista.

Aquí hay una tentativa:

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] 

EDITAR: La pregunta ahora menciona un temor a una "condición de carrera", que sólo puedo asumir que está siendo añadido/borrado mientras está el problema típico de los archivos en el proceso de tratar de elegir un archivo aleatorio.

No creo que haya una forma de evitarlo, aparte de tener en cuenta que cualquier operación de E/S es inherentemente "insegura", es decir, puede fallar. Por lo tanto, el algoritmo para abrir un archivo elegido al azar en un determinado directorio debe:

  • En realidad open() el archivo seleccionado, y manejar un fracaso, ya que el archivo ya no podría estar allí
  • Probablemente se limita a un conjunto número de intentos, por lo que no muere si el directorio está vacío o si ninguno de los archivos son legibles
+0

Sí, no sabía nada de eso, aunque lo vi en otra respuesta. Es bueno saberlo, gracias! – unwind

4

Solución de agnóstico del lenguaje:

1) Obtenga el total de no. de archivos en el directorio especificado.

2) Elija un número aleatorio de 0 a [total no. de archivos - 1].

3) Obtenga la lista de nombres de archivos como una colección adecuadamente indexada o similar.

4) Elija el enésimo elemento, donde n es el número aleatorio.

4

Si desea directorios incluidos, la respuesta de Yuval A. De lo contrario:

import os, random 

random.choice([x for x in os.listdir("C:\\") if os.path.isfile(os.path.join("C:\\", x))]) 
2

El problema con la mayoría de las soluciones dado se cargue todas sus aportaciones en la memoria, que pueden convertirse en un problema para las grandes entradas/jerarquías. Aquí hay una solución adaptada de The Perl Cookbook por Tom Christiansen y Nat Torkington. Para obtener un archivo al azar en cualquier lugar por debajo de un directorio:

#! /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 

Generalizando un poco hace una escritura a mano:

$ 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 
Cuestiones relacionadas