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?
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')]
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=True
depuis 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).
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 .
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.
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.
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")
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")
Il y a beaucoup de confusion sur ce sujet. Voyons si je peux clarifier (Python 3.7):
glob.glob('*.txt') :
associe tous les fichiers se terminant par '.txt' dans le répertoire en coursglob.glob('*/*.txt') :
same as 1glob.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 coursglob.glob('*.txt',recursive=True) :
same as 1glob.glob('*/*.txt',recursive=True) :
same as 3glob.glob('**/*.txt',recursive=True):
associe tous les fichiers se terminant par '.txt' dans le répertoire en cours et dans tous les sous-répertoiresIl est donc préférable de toujours spécifier recursive=True.
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\\**\\**")
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)
.