Búsqueda de subcarpetas recursivas y archivos de retorno en una lista de python

Estoy trabajando en una secuencia de comandos para ir recursivamente a través de subcarpetas en una carpeta principal y crear una lista a partir de un determinado tipo de archivo. Estoy teniendo un problema con el script. Actualmente se establece como sigue

for root, subFolder, files in os.walk(PATH): for item in files: if item.endswith(".txt") : fileNamePath = str(os.path.join(root,subFolder,item)) 

el problema es que la variable de subcarpeta está tirando de una lista de subcarpetas en lugar de la carpeta en la que se encuentra el archivo ITEM. Estaba pensando en ejecutar un bucle for para la subcarpeta antes y unirme a la primera parte de la ruta, pero pensé que volvería a verificar para ver si alguien tiene alguna sugerencia antes de eso. ¡Gracias por tu ayuda!

Deberías usar el dirpath que llamas root . Los dirnames se suministran para que pueda eliminarlos si hay carpetas en las que no desea que os.walk de ellas.

 import os result = [os.path.join(dp, f) for dp, dn, filenames in os.walk(PATH) for f in filenames if os.path.splitext(f)[1] == '.txt'] 

Editar:

Después de la última votación a la baja, se me ocurrió que glob es una mejor herramienta para seleccionar por extensión.

 import os from glob import glob result = [y for x in os.walk(PATH) for y in glob(os.path.join(x[0], '*.txt'))] 

También una versión de generador.

 from itertools import chain result = (chain.from_iterable(glob(os.path.join(x[0], '*.txt')) for x in os.walk('.'))) 

Edit2 para Python 3.4+

 from pathlib import Path result = list(Path(".").rglob("*.[tT][xX][tT]")) 

Cambiado en Python 3.5 : Soporte para globos recursivos usando “**”.

glob.glob() obtuvo un nuevo parámetro recursivo .

Si desea obtener todos los archivos .txt bajo my_path (recursivamente incluyendo subdirectorios):

 import glob files = glob.glob(my_path + '/**/*.txt', recursive=True) # my_path/ the dir # **/ every file and dir under my_path # *.txt every file that ends with '.txt' 

Si necesita un iterador puede usar iglob como alternativa:

 for file in glob.iglob(my_path, recursive=False): # ... 

Traduciré la comprensión de la lista de John La Rooy a anidada, en caso de que alguien más tenga problemas para entenderla.

 result = [y for x in os.walk(PATH) for y in glob(os.path.join(x[0], '*.txt'))] 

Debería ser equivalente a:

 result = [] for x in os.walk(PATH): for y in glob(os.path.join(x[0], '*.txt')): result.append(y) 

Aquí está la documentación para la comprensión de la lista y las funciones os.walk y glob.glob .

No es la respuesta más pythonica, pero la pondré aquí por diversión porque es una buena lección de recursión.

 def find_files( files, dirs=[], extensions=[]): new_dirs = [] for d in dirs: try: new_dirs += [ os.path.join(d, f) for f in os.listdir(d) ] except OSError: if os.path.splitext(d)[1] in extensions: files.append(d) if new_dirs: find_files(files, new_dirs, extensions ) else: return 

En mi máquina tengo dos carpetas, root y root2

 mender@multivax ]ls -R root root2 root: temp1 temp2 root/temp1: temp1.1 temp1.2 root/temp1/temp1.1: f1.mid root/temp1/temp1.2: f.mi f.mid root/temp2: tmp.mid root2: dummie.txt temp3 root2/temp3: song.mid 

Digamos que quiero encontrar todos los archivos .txt y .mid en cualquiera de estos directorios, entonces puedo hacer

 files = [] find_files( files, dirs=['root','root2'], extensions=['.mid','.txt'] ) print(files) #['root2/dummie.txt', # 'root/temp2/tmp.mid', # 'root2/temp3/song.mid', # 'root/temp1/temp1.1/f1.mid', # 'root/temp1/temp1.2/f.mid'] 

La nueva biblioteca pathlib simplifica esto a una línea:

 from pathlib import Path result = list(Path(PATH).glob('**/*.txt')) 

También puede utilizar la versión del generador:

 from pathlib import Path for file in Path(PATH).glob('**/*.txt'): pass 

Esto devuelve objetos de Path , que puede usar para casi cualquier cosa, u obtener el nombre del archivo como una cadena por file.name .