web-dev-qa-db-fra.com

Comment puis-je rechercher des sous-dossiers en utilisant le module glob.glob?

Je veux ouvrir une série de sous-dossiers dans un dossier, trouver des fichiers texte et imprimer des lignes de fichiers texte. J'utilise ceci:

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

Mais ceci ne peut pas accéder aux sous-dossiers également. Est-ce que quelqu'un sait comment utiliser la même commande pour accéder également à des sous-dossiers?

86
UserYmY

Dans Python 3.5 et versions ultérieures, utilisez la nouvelle fonctionnalité récursive **/:

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

Lorsque recursive est défini, ** suivi d'un séparateur de chemin correspond à 0 sous-répertoire ou plus.

Dans les versions antérieures de Python, glob.glob() ne peut pas répertorier les fichiers dans les sous-répertoires de manière récursive.

Dans ce cas, j'utiliserais os.walk() combiné avec fnmatch.filter() :

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

Cela va parcourir vos répertoires de manière récursive et renvoyer tous les chemins d'accès absolus dans les fichiers .txt correspondants. Dans ce cas spécifique , la fnmatch.filter() peut être excessive, vous pouvez également utiliser un test .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')]
129
Martijn Pieters

Pour rechercher des fichiers dans des sous-répertoires immédiats:

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

Pour une version récursive qui traverse tous les sous-répertoires, vous pouvez utiliser ** et passer recursive=Truedepuis Python 3.5 :

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

Les deux appels de fonction renvoient des listes. Vous pouvez utiliser glob.iglob() pour renvoyer les chemins un par un. Ou tilisez 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

Les deux méthodes renvoient des itérateurs (vous pouvez obtenir les chemins un par un).

18
jfs

Le paquet glob2 prend en charge les caractères génériques et est relativement rapide

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

Sur mon ordinateur portable, il faut environ 2 secondes pour faire correspondre > 60 000 chemins de fichiers .

17
megawac

Vous pouvez utiliser Formic avec Python 2.6

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

Divulgation - Je suis l'auteur de ce paquet.

8
Andrew Alcock

Voici une version adaptée qui active la fonctionnalité comme glob.glob sans utiliser 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

Donc si vous avez la structure de répertoire suivante

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

Vous pouvez faire quelque chose comme ça

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

En gros, le motif fnmatch correspond au nom de fichier entier, plutôt qu’au nom de fichier uniquement.

3
cevaris

Si vous utilisez Python 3.4+, vous pouvez utiliser le module pathlib . La méthode Path.glob() prend en charge le modèle **, qui signifie "ce répertoire et tous les sous-répertoires de manière récursive". Il retourne un générateur produisant des objets Path pour tous les fichiers correspondants.

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

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

Ne fonctionne pas dans tous les cas, utilisez plutôt glob2

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

Il y a beaucoup de confusion sur ce sujet. Voyons si je peux clarifier (Python 3.7):

  1. glob.glob('*.txt') : associe tous les fichiers se terminant par '.txt' dans le répertoire en cours
  2. glob.glob('*/*.txt') :same as 1
  3. glob.glob('**/*.txt') : associe tous les fichiers se terminant par '.txt' dans le sous-répertoires immédiats uniquement, mais pas dans le répertoire en cours
  4. glob.glob('*.txt',recursive=True) :same as 1
  5. glob.glob('*/*.txt',recursive=True) :same as 3
  6. glob.glob('**/*.txt',recursive=True): associe tous les fichiers se terminant par '.txt' dans le répertoire en cours et dans tous les sous-répertoires

Il est donc préférable de toujours spécifier recursive=True.

2
germ

Si vous pouvez installer le paquet glob2 ...

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

Tous les noms de fichiers et dossiers:

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

Comme l'a souligné Martijn, glob ne peut le faire que par l'intermédiaire de l'opérateur ** introduit dans Python 3.5. Puisque l'OP a explicitement demandé le module glob, les éléments suivants renverront un itérateur d'évaluation paresseux qui se comporte de la même manière.

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

Notez que vous ne pouvez itérer qu'une seule fois sur configfiles dans cette approche. Si vous avez besoin d'une liste réelle de fichiers de configuration pouvant être utilisés dans plusieurs opérations, vous devez la créer explicitement à l'aide de list(configfiles).

0
fxx