¿Cómo puedo buscar subcarpetas usando el módulo glob.glob?

Quiero abrir una serie de subcarpetas en una carpeta y encontrar algunos archivos de texto e imprimir algunas líneas de los archivos de texto. Estoy usando esto:

configfiles = glob.glob('C:/Users/sam/Desktop/file1/*.txt') 

Pero esto tampoco puede acceder a las subcarpetas. ¿Alguien sabe cómo puedo usar el mismo comando para acceder a las subcarpetas también?

En Python 3.5 y versiones posteriores, utilice la nueva funcionalidad recursiva **/ :

 configfiles = glob.glob('C:/Users/sam/Desktop/file1/**/*.txt', recursive=True) 

Cuando se establece recursive , ** seguido de un separador de ruta coincide con 0 o más subdirectorios.

En versiones anteriores de Python, glob.glob() no puede listar archivos en subdirectorios recursivamente.

En ese caso, usaría os.walk() combinado con fnmatch.filter() lugar:

 import os import fnmatch path = 'C:/Users/sam/Desktop/file1' configfiles = [os.path.join(dirpath, f) for dirpath, dirnames, files in os.walk(path) for f in fnmatch.filter(files, '*.txt')] 

Esto recorrerá los directorios de forma recursiva y devolverá todas las rutas de acceso absolutas a los archivos .txt correspondientes. En este caso específico, fnmatch.filter() puede ser una exageración, también puede usar la prueba .endswith() :

 import os path = 'C:/Users/sam/Desktop/file1' configfiles = [os.path.join(dirpath, f) for dirpath, dirnames, files in os.walk(path) for f in files if f.endswith('.txt')] 

El paquete glob2 admite comodines y es razonablemente rápido.

 code = ''' import glob2 glob2.glob("files/*/**") ''' timeit.timeit(code, number=1) 

En mi computadora portátil, toma aproximadamente 2 segundos coincidir con > 60,000 rutas de archivos .

Para buscar archivos en subdirectorios inmediatos:

 configfiles = glob.glob(r'C:\Users\sam\Desktop\*\*.txt') 

Para una versión recursiva que atraviesa todos los subdirectorios, puedes usar ** y pasar recursive=True desde Python 3.5 :

 configfiles = glob.glob(r'C:\Users\sam\Desktop\**\*.txt', recursive=True) 

Ambas llamadas de función devuelven listas. Podría usar glob.iglob() para devolver las rutas una por una. O use pathlib :

 from pathlib import Path path = Path(r'C:\Users\sam\Desktop') txt_files_only_subdirs = path.glob('*/*.txt') txt_files_all_recursively = path.rglob('*.txt') # including the current dir 

Ambos métodos devuelven iteradores (puede obtener rutas uno por uno).

Puedes usar Formic con Python 2.6

 import formic fileset = formic.FileSet(include="**/*.txt", directory="C:/Users/sam/Desktop/") 

Divulgación – Soy el autor de este paquete.

Aquí hay una versión adaptada que habilita la funcionalidad glob2 sin usar glob2 .

 def find_files(directory, pattern='*'): if not os.path.exists(directory): raise ValueError("Directory not found {}".format(directory)) matches = [] for root, dirnames, filenames in os.walk(directory): for filename in filenames: full_path = os.path.join(root, filename) if fnmatch.filter([full_path], pattern): matches.append(os.path.join(root, filename)) return matches 

Así que si tienes la siguiente estructura dir.

 tests/files ├── a0 │  ├── a0.txt │  ├── a0.yaml │  └── b0 │  ├── b0.yaml │  └── b00.yaml └── a1 

Puedes hacer algo como esto

 files = utils.find_files('tests/files','**/b0/b*.yaml') > ['tests/files/a0/b0/b0.yaml', 'tests/files/a0/b0/b00.yaml'] 

Más o menos la fnmatch patrón de fnmatch en el nombre de archivo completo, en lugar de solo el nombre de archivo.

configfiles = glob.glob('C:/Users/sam/Desktop/**/*.txt")

No funciona para todos los casos, en su lugar usa glob2

 configfiles = glob2.glob('C:/Users/sam/Desktop/**/*.txt") 

Si puedes instalar el paquete glob2 …

 import glob2 filenames = glob2.glob("C:\\top_directory\\**\\*.ext") # Where ext is a specific file extension folders = glob2.glob("C:\\top_directory\\**\\") 

Todos los nombres de archivos y carpetas:

 all_ff = glob2.glob("C:\\top_directory\\**\\**") 

Si está ejecutando Python 3.4+, puede usar el módulo pathlib . El método Path.glob() admite el patrón ** , que significa “este directorio y todos los subdirectorios, recursivamente”. Devuelve un generador que Path objetos de Path para todos los archivos coincidentes.

 from pathlib import Path configfiles = Path("C:/Users/sam/Desktop/file1/").glob("**/*.txt") 

Como señaló Martijn, glob solo puede hacer esto a través del operador ** introducido en Python 3.5. Como el OP solicitó explícitamente el módulo global, lo siguiente devolverá un iterador de evaluación perezoso que se comporta de manera similar

 import os, glob, itertools configfiles = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.txt')) for root, dirs, files in os.walk('C:/Users/sam/Desktop/file1/')) 

Tenga en cuenta que solo puede iterar una vez sobre los configfiles de configfiles en este enfoque. Si necesita una lista real de archivos de configuración que se pueden usar en múltiples operaciones, tendría que crear esto explícitamente mediante la list(configfiles) .