2012-05-04 17 views
5

Mi piacerebbe camminare in modo ricorsivo in una directory, ma voglio che python si interrompa da un singolo listdir se incontra una directory con più di 100 file. Fondamentalmente, sto cercando un file (.TXT), ma voglio evitare le directory con grandi sequenze di immagini DPX (di solito 10.000 file). Dal momento che i DPX vivono nelle directory da soli senza sottodirectory, vorrei interrompere il ciclo ASAP.Python Walk, ma Thread Lightly

Per farla breve, se Python incontra un file che corrisponde a ".DPX $" smette di elencare la sottodirectory, arretra, salta quella sottodirectory e continua il cammino in altre sottodirectory.

È possibile interrompere un ciclo di elenco di directory prima che vengano restituiti tutti i risultati dell'elenco?

+0

C'è qualcosa di distinto nei nomi delle directory contenenti sequenze di immagini DPX? –

+0

Se si desidera leggere le directory di grandi dimensioni in modo incrementale (ovvero non solo interrompere la ricorsione, ma nemmeno leggere i loro singoli contenuti), potrebbe essere necessario utilizzare qualcosa come le soluzioni descritte in http: // StackOverflow.it/questions/4403598/list-files-in-a-folder-come-a-stream-to-begin-process-immediatamente –

+0

Alcune directory hanno 'dpx' nel nome, ma non tutte :(@ charles, questo esempio funzionerà per me. Voglio uscire da un elenco se incrocio un DPX, in questo modo potrei evitare di scorrere tra 100.000 nomi di file, il che richiede molto tempo. – Jamie

risposta

1

Il modo corretto per evitare di allocare l'elenco di nomi utilizzando os.listdir consiste nell'utilizzare la funzione di livello os come ha detto @Charles Duffy.

Ispirato da questo altro post: List files in a folder as a stream to begin process immediately

ho aggiunto come risolvere il specifica domanda OP e utilizzato la versione rientrante delle funzioni.

from ctypes import CDLL, c_char_p, c_int, c_long, c_ushort, c_byte, c_char, Structure, POINTER, byref, cast, sizeof, get_errno 
from ctypes.util import find_library 

class c_dir(Structure): 
    """Opaque type for directory entries, corresponds to struct DIR""" 
    pass 

class c_dirent(Structure): 
    """Directory entry""" 
    # FIXME not sure these are the exactly correct types! 
    _fields_ = (
     ('d_ino', c_long), # inode number 
     ('d_off', c_long), # offset to the next dirent 
     ('d_reclen', c_ushort), # length of this record 
     ('d_type', c_byte), # type of file; not supported by all file system types 
     ('d_name', c_char * 4096) # filename 
     ) 
c_dirent_p = POINTER(c_dirent) 
c_dirent_pp = POINTER(c_dirent_p) 
c_dir_p = POINTER(c_dir) 

c_lib = CDLL(find_library("c")) 
opendir = c_lib.opendir 
opendir.argtypes = [c_char_p] 
opendir.restype = c_dir_p 

readdir_r = c_lib.readdir_r 
readdir_r.argtypes = [c_dir_p, c_dirent_p, c_dirent_pp] 
readdir_r.restype = c_int 

closedir = c_lib.closedir 
closedir.argtypes = [c_dir_p] 
closedir.restype = c_int 

import errno 

def listdirx(path): 
    """ 
    A generator to return the names of files in the directory passed in 
    """ 
    dir_p = opendir(path) 

    if not dir_p: 
     raise IOError() 

    entry_p = cast(c_lib.malloc(sizeof(c_dirent)), c_dirent_p) 

    try: 
     while True: 
      res = readdir_r(dir_p, entry_p, byref(entry_p)) 
      if res: 
       raise IOError() 
      if not entry_p: 
       break 
      name = entry_p.contents.d_name 
      if name not in (".", ".."): 
       yield name 
    finally: 
     if dir_p: 
      closedir(dir_p) 
     if entry_p: 
      c_lib.free(entry_p) 

if __name__ == '__main__': 
    import sys 
    path = sys.argv[1] 
    max_per_dir = int(sys.argv[2]) 
    for idx, entry in enumerate(listdirx(path)): 
     if idx >= max_per_dir: 
      break 
     print entry 
+0

Quindi invece di "se idx> = max_per_dir:" sostituire con: "se re.search ('\. DPX $', voce):" È così semplice? – Jamie

+0

sì, se trovi un file che termina con .DPX puoi ignorare quella directory. Ma la funzione non è ricorsiva, itererà solo su un singolo percorso. – fabrizioM

4

Se per "elenco directory ciclo" si intende os.listdir() quindi no. Questo non può essere rotto da. Potresti comunque vedere i metodi os.path.walk() o os.walk() e rimuovere semplicemente tutte le directory che contengono i file DPX. Se si utilizza os.walk() e si sta procedendo dall'alto verso il basso, si può influire su quali directory Python entra, semplicemente modificando l'elenco delle directory. os.path.walk() consente di scegliere dove si cammina con il metodo di visita.

+1

In particolare - ci sono alternative a 'os.listdir()' (cioè usando 'ctypes' per richiamare la chiamata di sistema sottostante) che _can_ –

+0

Come posso sapere se una directory ha un file DPX al suo interno evitando di leggere ogni file nella directory. Ci vogliono 30 minuti per elencare semplicemente le directory con DPX all'interno. 'Per esempio: root_dir /: -file.txt -subdir1/ --file1.txt --file2.txt --file3.txt -subdir2/ --file1.txt --file2.dpx ** * BREAK LOOP *** --subdir3/ --file1.txt --file2.txt --file3.txt '' – Jamie

+0

Utilizzando ctypes' e la lettura rientrante delle directory sono probabilmente la soluzione migliore come @Charles ha detto. Oppure potresti prendere in considerazione la scrittura di una directory specializzata che elenca la funzione come un modulo c python e la importa. Una qualche forma di reinserimento in c, sollevando un'eccezione se viene trovato un file DPX, importato come modulo sarebbe la soluzione più veloce, ma potenzialmente più complessa di una soluzione solo Python. Potenzialmente non però. – Will

2

Secondo il documentation per os.walk:

Quando top-down è True, il chiamante può modificare le dirnames elenco sul posto (ad esempio, tramite del o assegnamento di una fetta), e walk() sarà recurse solo nelle sottodirectory i cui nomi rimangono nei nomi ; questo può essere usato per potare la ricerca o per imporre un ordine specifico di visita. Modifica dirnames quando top-down è False è inefficace, in quanto le directory in dirnames sono già stati generati per il momento dirnames stesso è generato.

Quindi, in teoria, se si svuota fuori dirnames poi os.walk non si ricorsione verso il basso qualsiasi directory supplementari. Si noti il ​​commento su "... via del o assegnazione di sezioni"; non puoi semplicemente fare dirnames=[] perché questo non influirà sul contenuto dell'elenco dirnames.