2010-07-14 14 views
10

Ho una directory con un numero elevato di file (~ 1mil). Ho bisogno di scegliere un file casuale da questa directory. Dal momento che ci sono così tanti file, lo os.listdir richiede naturalmente un'eternità per finire.Scelta di un file casuale da una directory (con un numero elevato di file) in Python

C'è un modo per aggirare questo problema? Forse in qualche modo conoscere il numero di file nella directory (senza elencarlo) e scegliere il 'n'th file dove n è generato casualmente?

I file nella directory vengono assegnati in modo casuale.

+0

Che sistema operativo utilizzi? – danben

+0

2.6.30.10.1.amd64-smp # 1 x86_64 GNU/Linux – NoneType

+0

Si controllano i nomi dei file nella directory? – danben

risposta

1

Non sono sicuro che questo sia possibile. Anche a livello di VFS o di filesystem, non vi è alcuna garanzia che venga mantenuto un conteggio delle voci di directory. Ad esempio, molti filesystem registrano semplicemente le dimensioni combinate dei byte delle strutture di voci di directory contenute in una determinata directory.

La stima può essere effettuata se le voci della directory sono strutture di dimensioni fisse, ma ciò non è comune ora (si consideri LFN per FAT32). Anche se un determinato file system forniva un numero di voci senza necessità di iterare attraverso una directory, o se il VFS memorizzava nella cache un record di una lunghezza di directory, questi sarebbero sicuramente il sistema operativo, il filesystem e il kernel specifici.

+0

Potrebbe essere d'aiuto se tutti i file nella directory sono collegamenti simbolici? Sul mio sistema, tutti questi link hanno dimensioni di 512B. Quindi potremmo estrarre il numero di file usando questo e le informazioni combinate sulla dimensione della directory? – NoneType

+0

Sono molto fiducioso di aver sbagliato, sono ansioso di vedere una bella risposta tecnica alla tua domanda. –

0

Si può essere in grado di ottenere questo correre:

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

E questo è probabilmente la migliore soluzione possibile per il vostro problema, ma solo dove n è piccolo - se n va grande quindi è probabilmente os.listdir altrettanto buono per il tuo scopo.

Ho cercato e non ho trovato nessun altro modo per aprire un file in una directory. Se avessi più tempo sarei propenso a giocare un po 'e generare i miei file ~ 1mil.


ho solo pensato di un altro modo per farlo: Supponendo che i file sono costanti - non stai ricevendo più o meno - si potrebbe tenere un elenco dei nomi di file in un database SQLite. Quindi sarebbe relativamente semplice interrogare il database per un nome con un numero casuale ROWID. Non so se sarai ancora tormentato dal lungo tempo necessario per cercare il file corretto, ma almeno ottenere un nome file dovrebbe richiedere un po 'di tempo.

Ovviamente se i file nella directory vengono assegnati in modo casuale, è possibile rinominare i file (?) E inserirli in una struttura di directory come suggerisce AdamK.

+0

Proverò la funzione di generatore di 'listdir' insieme all'euristica di campionamento casuale suggerita da Nas Banov. (Ad esempio, campionamento uniforme su tutti i nomi di file mentre li si legge uno ad uno) – NoneType

0

provare questo, (qui è molto veloce con 50K file ...)

import glob 
import random 

list = glob.glob("*/*.*") 
print list[random.randrange(0,list.__len__())] 
+0

Richiede tempo di esecuzione altrettanto grande. – NoneType

+2

nota di pls 'random.randrange (0, lista .__ len __())' è scritto meglio come 'random.randrange (len (list))' –

3

Ahimè, non credo che ci sia una soluzione al vostro problema. Uno, non so di API portatile che ti restituirà il numero di voci nella directory (senza prima enumerarle). Due, non penso ci sia API per restituire la voce della directory per numero e non per nome.

Quindi, nel complesso, un programma dovrà enumerare le voci della directory O (n) per ottenere una singola scelta casuale. L'approccio banale di determinare il numero di voci e quindi selezionarne uno richiederà una quantità sufficiente di RAM per contenere l'elenco completo (os.listdir()) o dovrà enumerare la seconda volta la directory per trovare l'elemento casuale (n) - operazioni complessive n+n/2 in media.

C'è un approccio leggermente migliore - ma solo leggermente - vedere randomly-selecting-lines-from-files. In breve, c'è un modo per selezionare elementi casuali da elenco/iteratore con lunghezza sconosciuta, mentre si legge un elemento alla volta e assicurarsi che qualsiasi oggetto possa essere selezionato con uguale probabilità. Ma questo non aiuterà con os.listdir() perché restituisce già list in memoria che contiene già tutte le voci + 1M - in modo da poter anche chiedere che circa len() ...

+0

Questa è una buona idea, sono tentato di provare questo usando il 'os .listdir' la funzione di generatore che Wayne suggeriva. – NoneType

+0

@NoneType: se ti va di giocarci, certo. Ma non credo che un miglioramento di solo 2 volte valga la pena; dovresti girare per qualcosa di lineare o logaritmico. Per questo però dovresti essere in grado di cambiare il problema in qualche modo ... perché esattamente hai bisogno di fare questa selezione casuale di file, qual è la necessità dietro di esso? Hai una conoscenza migliore dello schema di denominazione dei file? –

1

Ho un bisogno simile al PO.

Penso che adotterò un metodo di precaching: memorizzi in un file .txt l'elenco di tutti i file, quindi puoi semplicemente fare una ricerca intelligente di una riga a caso nella tua inserzione (senza nemmeno doverla caricare in memoria), e il gioco è fatto!

Naturalmente, si devono ancora aggiornare la cache, e ancora più importante definire quando è necessario aggiornare la cache, ma a seconda delle esigenze, può essere facile (subito dopo una specifica azione, o quando qualcosa è cambiato , eccetera..).

Un codice per leggere abilmente una riga a caso da un file, in Python, da Jonathan Kupferman:

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

Problemi correlati