2009-03-31 6 views
16

Qual è il modo migliore per scegliere un file casuale da una directory in Python?Il modo migliore per scegliere un file casuale da una directory

Edit: Qui è quello che sto facendo:

import os 
import random 
import dircache 

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

È questo particolarmente grave, o c'è un modo particolarmente migliore?

+0

Scusate ragazzi, ho presentato accidentalmente prima che finissi di entrare la mia domanda. Non dovrebbe cambiare molto però. – JasonSmith

+0

Potrebbe chiarire il problema delle condizioni di gara? Suppongo che tu voglia selezionare e aprire un file senza finestre intermedie (quando qualcuno potrebbe eliminarlo tra scelta e tentativo di apertura() ad esempio), ma potrebbe essere utile dichiararlo esplicitamente (supponendo che ti sto interpretando correttamente). – Brian

+0

È la condizione di competizione perché più processi lo faranno contemporaneamente? O si verificherà la condizione della gara perché c'è uno scrittore che crea file e questo lettore che li sta selezionando? –

risposta

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

quanto riguarda la tua domanda modificato: in primo luogo, ho un ssume di conoscere i rischi dell'uso di dircache e del fatto che sia deprecated since 2.6, and removed in 3.0.

In secondo luogo, non vedo dove siano presenti condizioni di competizione. L'oggetto dircache è sostanzialmente immutabile (dopo che l'elenco delle directory è stato memorizzato nella cache, non viene mai più letto), quindi nessun danno nelle letture simultanee da esso.

Oltre a ciò, non capisco perché si riscontrino problemi con questa soluzione. Va bene.

+1

Grazie per aver detto che dircache è deprecato. –

1

Indipendente dalla lingua utilizzata, è possibile leggere tutti i riferimenti ai file in una directory in una struttura dati come una matrice (qualcosa come "listFiles"), ottenere la lunghezza della matrice. calcola un numero casuale nell'intervallo tra "0" e "arrayLength-1" e accedi al file nell'indice specifico. Questo dovrebbe funzionare, non solo in Python.

1

Se non si conosce in anticipo quali file ci sono, sarà necessario ottenere un elenco, quindi selezionare un indice casuale nell'elenco.

Ecco un tentativo:

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] 

EDIT: La questione ora parla di un timore di una "race condition", che posso solo supporre è il problema tipico dei file viene aggiunto/rimosso mentre si è nel processo di cercare di scegliere un file casuale.

Non credo che ci sia un modo per aggirare questo, oltre a tenere a mente che qualsiasi operazione di I/O è intrinsecamente "non sicura", cioè può fallire. Quindi, l'algoritmo per aprire un file scelto a caso in una data directory dovrebbe:

  • realtà open() il file selezionato, e gestire un fallimento, dal momento che il file potrebbe non essere più lì
  • Probabilmente si limita a un set numero di tentativi, in modo che non muore se la directory è vuota o se nessuno dei file sono leggibili
+0

Sì, non lo sapevo, l'ho visto in un'altra risposta. Buono a sapersi, grazie! – unwind

4

Soluzione agnostica per lingua:

1) Ottenere il totale n. di file nella directory specificata.

2) Selezionare un numero casuale da 0 a [numero totale. di file - 1].

3) Ottenere l'elenco dei nomi di file come una raccolta indicizzata in modo appropriato o simile.

4) Scegliere l'ennesimo elemento, dove n è il numero casuale.

4

Se si desidera includere le directory, la risposta di Yuval A. In caso contrario:

import os, random 

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

Il problema con la maggior parte delle soluzioni di data è di caricare tutti i vostri input in memoria, che può diventare un problema per i grandi ingressi/gerarchie. Ecco una soluzione adattata da The Perl Cookbook di Tom Christiansen e Nat Torkington. Per ottenere un file casuale ovunque sotto una directory:

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

Generalizzando un po 'fa uno script a portata di 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