2012-05-04 7 views
5

Me gustaría recorrer un directorio de manera recursiva, pero quiero que Python se separe de cualquier listdir si encuentra un directorio con más de 100 archivos. Básicamente, estoy buscando un archivo (.TXT), pero quiero evitar directorios con grandes secuencias de imágenes DPX (por lo general, 10.000 archivos). Como los DPX viven en directorios por sí mismos sin subdirectorios, me gustaría romper ese bucle lo antes posible.Python Walk, pero Thread Lightly

En resumen, si python encuentra un archivo que coincida con ".DPX $", deja de enumerar el subdirectorio, da marcha atrás, se salta ese subdirectorio y continúa el recorrido en otros subdirectorios.

¿Es posible romper un bucle de listado de directorios antes de que se devuelvan todos los resultados de la lista?

+0

¿Hay algo distinto acerca de los nombres de directorio que contienen secuencias de imágenes DPX? –

+0

Si desea leer grandes directorios de forma incremental (es decir, no solo detener la recursión, pero ni siquiera leer sus contenidos individuales), es posible que necesite usar algo como las soluciones descritas en http: // stackoverflow.com/questions/4403598/list-files-in-a-folder-as-a-stream-to-begin-process-inmediatamente –

+0

Algunos directorios tienen 'dpx' en el nombre, pero no todos ellos :(@charles, ¿ese ejemplo funciona para mí. Quiero salir de una lista si cruzo un DPX, de esta manera podría evitar iterar a través de 100.000 nombres de archivo, lo que lleva mucho tiempo. – Jamie

Respuesta

1

La forma correcta de evitar la asignación de la lista de nombres usando os.listdir es usar la función de nivel de os como dijo @Charles Duffy.

inspirado en este otro mensaje: List files in a folder as a stream to begin process immediately

que añade la forma de resolver la cuestión OP específica y se utiliza la versión reentrante de la función.

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

"si idx> = max_per_dir:" Reemplazar con: "si re.search ('\ DPX $.', La entrada):" Es así de simple? – Jamie

+0

sí, si encuentra un archivo que finaliza con .DPX, puede ignorar ese directorio. Pero la función no es recursiva, solo iterará sobre una sola ruta. – fabrizioM

4

Si por 'bucle de lista de directorios' te refieres os.listdir(), entonces no. Esto no se puede romper. Sin embargo, puede mirar los métodos os.path.walk() o os.walk() y simplemente eliminar todos los directorios que contienen DPX archivos. Si usa os.walk() y está caminando de arriba hacia abajo, puede afectar las direcciones en las que Python entra simplemente modificando la lista de directorios. os.path.walk() le permite elegir dónde camina con el método de visita.

+1

Cabe destacar que existen alternativas a 'os.listdir()' (es decir, que utiliza 'ctypes' para invocar la llamada al sistema subyacente) que _can_ hacerse de forma incremental. –

+0

Cómo puedo saber si un directorio tiene un archivo DPX mientras evita leer cada archivo en el directorio. Lleva 30 minutos simplemente enumerar los directorios con DPX dentro. 'Por ejemplo: ROOT_DIR /: -file.txt -subdir1/ --file1.txt --file2.txt --file3.txt -subdir2/ --file1.txt --file2.dpx ** * rotura de lazo *** --subdir3/ --file1.txt --file2.txt --file3.txt '' – Jamie

+0

Usando ctypes' y la lectura re-entrante del directorio son probablemente la mejor opción como @Charles dijo. O podría considerar escribir una función de listado de directorios especializados como un módulo c python e importarlo. Alguna forma de listado de reentrantes en c, generando una excepción si se encuentra un archivo DPX, importado como un módulo sería la solución más rápida, pero potencialmente más compleja que una solución de python. Potencialmente no sin embargo. Así que en lugar de – Will

2

Según la documentation para os.walk:

Cuando de arriba hacia abajo es True, la persona que llama puede modificar los dirnames lista en contexto (por ejemplo, a través de del o asignación rebanada), y walk() se solo recurse en los subdirectorios cuyos nombres permanecen en dirnames; esto se puede usar para podar la búsqueda, o para imponer un orden específico de visita. La modificación de dirnames cuando de arriba hacia abajo es False es ineficaz, ya que los directorios en dirnames ya han sido generados por el momento dirnames sí se genera .

Por lo tanto, en teoría, si se vacían dirnamesos.walk entonces no habrá ningún recursivo abajo directorios adicionales. Tenga en cuenta el comentario sobre "... a través de la asignación de división"; simplemente no puede hacer dirnames=[] porque esto no afectará el contenido de la lista dirnames.