¿Cómo utilizar para buscar archivos de forma recursiva?

Resuelto Ben Gartner asked hace 14 años • 28 respuestas

Me gustaría enumerar todos los archivos de forma recursiva en un directorio. Actualmente tengo una estructura de directorios como esta:

  • src/main.c
  • src/dir/file1.c
  • src/another-dir/file2.c
  • src/another-dir/nested/files/file3.c

Intenté hacer lo siguiente:

from glob import glob

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

Pero esto solo obtendrá archivos directamente en la srcsubcarpeta, por ejemplo, obtengo main.cpero no obtendré file1.c, file2.cetc.

from glob import glob

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 complicado, ¿cómo puedo hacerlo correctamente?

Ben Gartner avatar Feb 03 '10 01:02 Ben Gartner
Aceptado

Hay un par de maneras:

rutalib.Ruta().rglob()

Úselo pathlib.Path().rglob()desde el pathlibmódulo, que se introdujo en Python 3.5.

from pathlib import Path

for path in Path('src').rglob('*.c'):
    print(path.name)

glob.glob()

Si no desea utilizar pathlib, utilice glob.glob():

from glob import glob

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

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

os.walk()

Para versiones anteriores de Python, utilícelo os.walk()para recorrer recursivamente un directorio y fnmatch.filter()compararlo 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))

Esta versión también debería ser más rápida dependiendo de cuántos archivos tenga, ya que el módulo pathlib tiene un poco de sobrecarga sobre os.walk().

Johan Dahlin avatar Feb 02 '2010 18:02 Johan Dahlin

Para Python >= 3.5 puedes usar **, recursive=True, es decir:

import glob
for f in glob.glob('/path/**/*.c', recursive=True):
    print(f)

Si recursivo es True(predeterminado False), el patrón ** coincidirá con cualquier archivo y cero o más directoriesysubdirectories . Si el patrón va seguido de os.sep, solo directorios y subdirectoriescoincidencias.


Demostración de Python 3

Pedro Lobito avatar Aug 25 '2019 09:08 Pedro Lobito

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

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 tal como se encuentra, en lugar de buscar todos los archivos y luego procesarlos.

Bruno Oliveira avatar Feb 02 '2010 18:02 Bruno Oliveira

Modifiqué el módulo glob para admitir ** el globbing recursivo, por ejemplo:

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

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

Útil cuando desea brindarles a sus usuarios la capacidad de usar la sintaxis ** y, por lo tanto, os.walk() por sí solo no es lo suficientemente bueno.

miracle2k avatar Jun 26 '2011 14:06 miracle2k

A partir de Python 3.4, se puede utilizar el glob()método de una de las Pathclases del 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, la misma sintaxis también es compatible con glob.glob().

taleinat avatar Nov 11 '2014 16:11 taleinat