Question Utilisez un Glob () pour trouver des fichiers récursivement en Python?


C'est ce que j'ai:

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

mais je veux rechercher les sous-dossiers de src. Quelque chose comme ça fonctionnerait:

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

Mais c'est évidemment limité et maladroit.


496
2018-02-02 18:19


origine


Réponses:


Python 3.5+

A partir de Python version 3.5, le glob le module prend en charge le "**" directive (qui n'est analysée que si vous réussissez recursive drapeau):

import glob

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

Si vous avez besoin d'une liste, utilisez simplement glob.glob au lieu de glob.iglob.

Pour les cas où les fichiers correspondants commençant par un point (.); comme les fichiers dans le répertoire en cours ou les fichiers cachés sur un système basé sur Unix, utilisez le os.walk solution ci-dessous.

Python 2.2 à 3.4

Pour les anciennes versions de Python, en commençant par Python 2.2, utilisez os.walk parcourir récursivement un répertoire et fnmatch.filter correspondre à une expression 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 et plus tôt

Pour les versions Python encore plus anciennes, utilisez glob.glob contre chaque nom de fichier au lieu de fnmatch.filter.


963
2018-02-02 18:26



Semblable à d'autres solutions, mais en utilisant fnmatch.fnmatch au lieu de glob, car os.walk a déjà répertorié les noms de fichiers:

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

En outre, l'utilisation d'un générateur vous permet de traiter chaque fichier tel qu'il est trouvé, au lieu de rechercher tous les fichiers. et alors les traiter.


95
2018-02-02 18:44



J'ai modifié le module glob pour prendre en charge ** la globalisation récursive, par exemple:

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

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

Utile lorsque vous souhaitez donner à vos utilisateurs la possibilité d'utiliser la syntaxe **, et donc que os.walk () ne suffit pas.


51
2018-06-26 14:14



A partir de Python 3.4, on peut utiliser le glob() méthode de l'un des Path classes dans le nouveau pathlib module, qui prend en charge ** jokers Par exemple:

from pathlib import Path

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

Mettre à jour: À partir de Python 3.5, la même syntaxe est également prise en charge par glob.glob().


43
2017-11-11 16:08



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 vous donne exactement les mêmes motifs que glob, donc c'est vraiment un excellent remplacement pour glob.glob avec une sémantique très proche. Une version itérative (par exemple un générateur), IOW un remplacement pour glob.iglob, est une adaptation triviale (juste yield les résultats intermédiaires que vous allez, au lieu de extendune liste de résultats unique à retourner à la fin).


37
2018-02-02 18:39



Vous voudrez utiliser os.walk pour collecter des noms de fichiers correspondant à vos critères. Par exemple:

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))

20
2018-02-02 18:24



Voici une solution avec des compréhensions de listes imbriquées, os.walk et simple suffixe correspondant au lieu 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')]

Il peut être compressé en une seule ligne:

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

ou généralisé en fonction:

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 vous avez besoin de plein glob modèles de style, vous pouvez suivre Alex et L'exemple de Bruno et son utilisation 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')

13
2017-11-02 08:10



Johan et Bruno apportent d'excellentes solutions quant à l'exigence minimale énoncée. Je viens de sortir Formique qui implémente Ant FileSet et Globs qui peut gérer cela et des scénarios plus compliqués. Une mise en œuvre de votre exigence est:

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

5
2018-05-15 08:53



basé sur d'autres réponses c'est mon implémentation de travail actuelle, qui récupère les fichiers xml imbriqués dans un répertoire racine:

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

Je m'amuse vraiment avec python :)


5
2017-07-28 22:09