¿Cómo usar glob () para encontrar archivos de forma recursiva?

Esto es lo que tengo:

glob(os.path.join('src','*.c')) 

pero quiero buscar las subcarpetas de src. Algo como esto funcionaría:

 glob(os.path.join('src','*.c')) glob(os.path.join('src','*','*.c')) glob(os.path.join('src','*','*','*.c')) glob(os.path.join('src','*','*','*','*.c')) 

Pero esto es obviamente limitado y torpe.

Python 3.5+

A partir de la versión 3.5 de Python, el módulo glob admite la directiva "**" (que se analiza solo si se pasa el indicador recursive ):

 import glob for filename in glob.iglob('src/**/*.c', recursive=True): print(filename) 

Si necesita una lista, simplemente use glob.glob lugar de glob.iglob .

Para casos donde coincidan los archivos que comienzan con un punto (.); como archivos en el directorio actual o archivos ocultos en el sistema basado en Unix, use la solución os.walk continuación.

Python 2.2 a 3.4

Para versiones anteriores de Python, comenzando con Python 2.2, use os.walk para recorrer un directorio de forma recursiva y fnmatch.filter para que coincida con una expresión simple:

 import fnmatch import os matches = [] for root, dirnames, filenames in os.walk('src'): for filename in fnmatch.filter(filenames, '*.c'): matches.append(os.path.join(root, filename)) 

Python 2.1 y anteriores

Incluso para versiones más antiguas de Python, use glob.glob contra cada nombre de archivo en lugar de fnmatch.filter .

Similar a otras soluciones, pero usando fnmatch.fnmatch en lugar de glob, ya que os.walk ya enumeró los nombres de archivo:

 import os, fnmatch def find_files(directory, pattern): for root, dirs, files in os.walk(directory): for basename in files: if fnmatch.fnmatch(basename, pattern): filename = os.path.join(root, basename) yield filename for filename in find_files('src', '*.c'): print 'Found C source:', filename 

Además, el uso de un generador le permite procesar cada archivo a medida que se encuentra, en lugar de encontrar todos los archivos y luego procesarlos.

He modificado el módulo glob para que sea compatible con ** para globazas recursivas, por ejemplo:

 >>> import glob2 >>> all_header_files = glob2.glob('src/**/*.c') 

https://github.com/miracle2k/python-glob2/

Es útil cuando quiere proporcionar a sus usuarios la capacidad de usar la syntax **, y por lo tanto, os.walk () solo no es lo suficientemente bueno.

A partir de Python 3.4, se puede usar el método glob() de una de las clases de Path en el nuevo módulo pathlib , que admite ** comodines. Por ejemplo:

 from pathlib import Path for file_path in Path('src').glob('**/*.c'): print(file_path) # do whatever you need with these files 

Actualización: A partir de Python 3.5, glob.glob() también admite la misma syntax.

 import os import fnmatch def recursive_glob(treeroot, pattern): results = [] for base, dirs, files in os.walk(treeroot): goodfiles = fnmatch.filter(files, pattern) results.extend(os.path.join(base, f) for f in goodfiles) return results 

fnmatch te da exactamente los mismos patrones que glob , por lo que este es realmente un excelente reemplazo para glob.glob con una semántica muy cercana. Una versión iterativa (p. Ej., Un generador), glob.iglob , un reemplazo para glob.iglob , es una adaptación trivial (solo yield los resultados intermedios a medida que glob.iglob , en lugar de extend una lista de resultados única para devolver al final).

os.walk usar os.walk para recostackr nombres de archivos que coincidan con sus criterios. Por ejemplo:

 import os cfiles = [] for root, dirs, files in os.walk('src'): for file in files: if file.endswith('.c'): cfiles.append(os.path.join(root, file)) 

Aquí hay una solución con listas de comprensión anidadas, os.walk y coincidencia de sufijo simple en lugar de glob :

 import os cfiles = [os.path.join(root, filename) for root, dirnames, filenames in os.walk('src') for filename in filenames if filename.endswith('.c')] 

Se puede comprimir en una sola línea:

 import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')] 

o generalizada como una función:

 import os def recursive_glob(rootdir='.', suffix=''): return [os.path.join(looproot, filename) for looproot, _, filenames in os.walk(rootdir) for filename in filenames if filename.endswith(suffix)] cfiles = recursive_glob('src', '.c') 

Si necesita patrones de estilo glob , puede seguir el ejemplo de Alex y Bruno y usar fnmatch :

 import fnmatch import os def recursive_glob(rootdir='.', pattern='*'): return [os.path.join(looproot, filename) for looproot, _, filenames in os.walk(rootdir) for filename in filenames if fnmatch.fnmatch(filename, pattern)] cfiles = recursive_glob('src', '*.c') 

Johan y Bruno proporcionan excelentes soluciones en los requisitos mínimos tal como se indica. Acabo de lanzar Formic que implementa Ant FileSet y Globs que pueden manejar esto y otros escenarios más complicados. Una implementación de su requerimiento es:

 import formic fileset = formic.FileSet(include="/src/**/*.c") for file_name in fileset.qualified_files(): print file_name 

en base a otras respuestas, esta es mi implementación actual, que recupera archivos xml nesteds en un directorio raíz:

 files = [] for root, dirnames, filenames in os.walk(myDir): files.extend(glob.glob(root + "/*.xml")) 

Realmente me estoy divirtiendo con python 🙂

Recientemente tuve que recuperar mis fotos con la extensión .jpg. Corrí photorec y recuperé 4579 directorios con 2,2 millones de archivos en el interior, con una gran variedad de extensiones. Con el script a continuación, pude seleccionar 50133 archivos con extensión .jpg en cuestión de minutos:

 #!/usr/binenv python2.7 import glob import shutil import os src_dir = "/home/mustafa/Masaüstü/yedek" dst_dir = "/home/mustafa/Genel/media" for mediafile in glob.iglob(os.path.join(src_dir, "*", "*.jpg")): #"*" is for subdirectory shutil.copy(mediafile, dst_dir) 

Otra forma de hacerlo solo con el módulo glob. Simplemente agregue el método rglob con un directorio base de inicio y un patrón para que coincida y se mostrará una lista de nombres de archivos coincidentes.

 import glob import os def _getDirs(base): return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ] def rglob(base, pattern): list = [] list.extend(glob.glob(os.path.join(base,pattern))) dirs = _getDirs(base) if len(dirs): for d in dirs: list.extend(rglob(os.path.join(base,d), pattern)) return list 

Acaba de hacer esto .. se imprimirán los archivos y directorios de forma jerárquica

Pero no utilicé fnmatch o walk

 #!/usr/bin/python import os,glob,sys def dirlist(path, c = 1): for i in glob.glob(os.path.join(path, "*")): if os.path.isfile(i): filepath, filename = os.path.split(i) print '----' *c + filename elif os.path.isdir(i): dirname = os.path.basename(i) print '----' *c + dirname c+=1 dirlist(i,c) c-=1 path = os.path.normpath(sys.argv[1]) print(os.path.basename(path)) dirlist(path) 

Además de las respuestas sugeridas, puede hacer esto con un poco de generación perezosa y lista de comprensión mágica:

 import os, glob, itertools results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c')) for root, dirs, files in os.walk('src')) for f in results: print(f) 

Además de encajar en una línea y evitar listas innecesarias en la memoria, esto también tiene el efecto secundario agradable, que puede usarlo de manera similar al operador **, por ejemplo, podría usar os.path.join(root, 'some/path/*.c') para obtener todos los archivos .c en todos los subdirectorios de src que tienen esta estructura.

Versión simplificada de la respuesta de Johan Dahlin, sin fnmatch .

 import os matches = [] for root, dirnames, filenames in os.walk('src'): matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c'] 

O con una lista de comprensión:

  >>> base = r"c:\User\xtofl" >>> binfiles = [ os.path.join(base,f) for base, _, files in os.walk(root) for f in files if f.endswith(".jpg") ] 

Ese uno usa fnmatch o expresión regular:

 import fnmatch, os def filepaths(directory, pattern): for root, dirs, files in os.walk(directory): for basename in files: try: matched = pattern.match(basename) except AttributeError: matched = fnmatch.fnmatch(basename, pattern) if matched: yield os.path.join(root, basename) # usage if __name__ == '__main__': from pprint import pprint as pp import re path = r'/Users/hipertracker/app/myapp' pp([x for x in filepaths(path, re.compile(r'.*\.py$'))]) pp([x for x in filepaths(path, '*.py')]) 

Aquí está mi solución utilizando la comprensión de lista para buscar múltiples extensiones de archivo de forma recursiva en un directorio y todos los subdirectorios:

 import os, glob def _globrec(path, *exts): """ Glob recursively a directory and all subdirectories for multiple file extensions Note: Glob is case-insensitive, ie for '\*.jpg' you will get files ending with .jpg and .JPG Parameters ---------- path : str A directory name exts : tuple File extensions to glob for Returns ------- files : list list of files matching extensions in exts in path and subfolders """ dirs = [a[0] for a in os.walk(path)] f_filter = [d+e for d in dirs for e in exts] return [f for files in [glob.iglob(files) for files in f_filter] for f in files] my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif') for f in my_pictures: print f 
 import sys, os, glob dir_list = ["c:\\books\\heap"] while len(dir_list) > 0: cur_dir = dir_list[0] del dir_list[0] list_of_files = glob.glob(cur_dir+'\\*') for book in list_of_files: if os.path.isfile(book): print(book) else: dir_list.append(book) 

Modifiqué la respuesta principal en esta publicación … y recientemente creé esta secuencia de comandos que recorrerá todos los archivos en un directorio determinado (searchdir) y los subdirectorios debajo de él … e imprime el nombre de archivo, rootdir, fecha de creación / modificación, y tamaño.

Espero que esto ayude a alguien … y puedan recorrer el directorio y obtener información de archivo.

 import time import fnmatch import os def fileinfo(file): filename = os.path.basename(file) rootdir = os.path.dirname(file) lastmod = time.ctime(os.path.getmtime(file)) creation = time.ctime(os.path.getctime(file)) filesize = os.path.getsize(file) print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize) searchdir = r'D:\Your\Directory\Root' matches = [] for root, dirnames, filenames in os.walk(searchdir): ## for filename in fnmatch.filter(filenames, '*.c'): for filename in filenames: ## matches.append(os.path.join(root, filename)) ##print matches fileinfo(os.path.join(root, filename)) 

Aquí hay una solución que hará coincidir el patrón con la ruta completa y no solo con el nombre de archivo base.

Utiliza fnmatch.translate para convertir un patrón de estilo glob en una expresión regular, que luego se compara con la ruta completa de cada archivo encontrado mientras recorre el directorio.

re.IGNORECASE es opcional, pero deseable en Windows ya que el sistema de archivos en sí no re.IGNORECASE mayúsculas y minúsculas. (No me molesté en comstackr la expresión regular porque los documentos indican que debe guardarse en caché internamente).

 import fnmatch import os import re def findfiles(dir, pattern): patternregex = fnmatch.translate(pattern) for root, dirs, files in os.walk(dir): for basename in files: filename = os.path.join(root, basename) if re.search(patternregex, filename, re.IGNORECASE): yield filename 

Necesitaba una solución para Python 2.x que funcione rápidamente en directorios grandes.
Terminé con esto:

 import subprocess foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True) for foundfile in foundfiles.splitlines(): print foundfile 

Tenga en cuenta que es posible que necesite un manejo de excepciones en caso de que ls no encuentre ningún archivo coincidente.