Existe-t-il un meilleur moyen d’utiliser glob.glob dans python pour obtenir une liste de plusieurs types de fichiers, tels que .txt, .mdown et .markdown? En ce moment j'ai quelque chose comme ça:
projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') )
projectFiles2 = glob.glob( os.path.join(projectDir, '*.mdown') )
projectFiles3 = glob.glob( os.path.join(projectDir, '*.markdown') )
Peut-être y a-t-il un meilleur moyen, mais que diriez-vous de:
>>> import glob
>>> types = ('*.pdf', '*.cpp') # the Tuple of file types
>>> files_grabbed = []
>>> for files in types:
... files_grabbed.extend(glob.glob(files))
...
>>> files_grabbed # the list of pdf and cpp files
Peut-être y a-t-il un autre moyen, alors attendez au cas où quelqu'un d'autre proposerait une meilleure réponse.
from glob import glob
files = glob('*.gif')
files.extend(glob('*.png'))
files.extend(glob('*.jpg'))
print(files)
Si vous devez spécifier un chemin, placez des motifs de correspondance en boucle et conservez la jointure à l'intérieur de la boucle pour plus de simplicité:
from os.path import join
from glob import glob
files = []
for ext in ('*.gif', '*.png', '*.jpg'):
files.extend(glob(join("path/to/dir", ext)))
print(files)
Enchaînez les résultats:
import itertools as it, glob
def multiple_file_types(*patterns):
return it.chain.from_iterable(glob.iglob(pattern) for pattern in patterns)
Ensuite:
for filename in multiple_file_types("*.txt", "*.sql", "*.log"):
# do stuff
glob
renvoie une liste: pourquoi ne pas l'exécuter plusieurs fois et concaténer les résultats?
from glob import glob
ProjectFiles = glob('*.txt') + glob('*.mdown') + glob('*markdown')
avec glob ce n'est pas possible. vous ne pouvez utiliser que:
* correspond à tout
? correspond à n'importe quel caractère
[seq] correspond à n'importe quel caractère de seq
[! seq] correspond à tout caractère ne se trouvant pas dans seq
utilisez os.listdir et une expression rationnelle pour vérifier les motifs:
for x in os.listdir('.'):
if re.match('.*\.txt|.*\.sql', x):
print x
Par exemple, pour *.mp3
et *.flac
sur plusieurs dossiers, vous pouvez faire:
mask = r'music/*/*.[mf][pl][3a]*'
glob.glob(mask)
L'idée peut être étendue à plusieurs extensions de fichiers, mais vous devez vérifier que les combinaisons ne correspondent à aucune autre indésirable. extension de fichier que vous pouvez avoir sur ces dossiers. Donc, soyez prudent avec cela.
Pour combiner automatiquement une liste d'extensions arbitraire dans un seul modèle glob, vous pouvez procéder comme suit:
mask_base = r'music/*/*.'
exts = ['mp3', 'flac', 'wma']
chars = ''.join('[{}]'.format(''.join(set(c))) for c in Zip(*exts))
mask = mask_base + chars + ('*' if len(set(len(e) for e in exts)) > 1 else '')
print(mask) # music/*/*.[fmw][plm][3a]*
Un one-liner, juste pour l'enfer ..
folder = "C:\\multi_pattern_glob_one_liner"
files = [item for sublist in [glob.glob(folder + ext) for ext in ["/*.txt", "/*.bat"]] for item in sublist]
sortie:
['C:\\multi_pattern_glob_one_liner\\dummy_txt.txt', 'C:\\multi_pattern_glob_one_liner\\dummy_bat.bat']
Après être venu ici pour chercher de l'aide, j'ai créé ma propre solution et je voulais la partager. C'est basé sur la réponse de user2363986, mais je pense que c'est plus évolutif. Cela signifie que si vous avez 1000 extensions, le code aura toujours un aspect élégant.
from glob import glob
directoryPath = "C:\\temp\\*."
fileExtensions = [ "jpg", "jpeg", "png", "bmp", "gif" ]
listOfFiles = []
for extension in fileExtensions:
listOfFiles.extend( glob( directoryPath + extension ))
for file in listOfFiles:
print(file) # Or do other stuff
Voici une variante de compréhension de liste à une ligne de la réponse de Pat (qui inclut également ce que vous vouliez placer dans un répertoire de projet spécifique):
import os, glob
exts = ['*.txt', '*.mdown', '*.markdown']
files = [f for ext in exts for f in glob.glob(os.path.join(project_dir, ext))]
Vous passez en boucle sur les extensions (for ext in exts
), Puis pour chaque extension, vous prenez chaque fichier correspondant au motif global (for f in glob.glob(os.path.join(project_dir, ext)
).
Cette solution est courte et ne contient aucune boucle inutile, aucune compréhension de liste imbriquée ni aucune fonction d'encombrement du code. Juste pur, expressif, Pythonic Zen .
Cette solution vous permet d’avoir une liste personnalisée de exts
pouvant être modifiée sans avoir à mettre à jour votre code. (C'est toujours une bonne pratique!)
La liste de compréhension est la même que celle utilisée dans la solution de Laurent (pour laquelle j'ai voté). Mais je dirais qu'il n'est généralement pas nécessaire d'affecter une seule ligne à une fonction distincte, c'est pourquoi je propose cela comme solution alternative.
Bonus:
Si vous devez rechercher non seulement un seul répertoire, mais également tous les sous-répertoires, vous pouvez passer recursive=True
Et utiliser le symbole global multi-répertoires **
. 1:
files = [f for ext in exts
for f in glob.glob(os.path.join(project_dir, '**', ext), recursive=True)]
Ceci invoquera glob.glob('<project_dir>/**/*.txt', recursive=True)
et ainsi de suite pour chaque extension.
1 Techniquement, le symbole glob **
Correspond simplement à un ou plusieurs caractères , y compris la barre oblique /
(Contrairement au singulier *
Symbole glob). En pratique, vous devez simplement vous rappeler que tant que vous entourez **
De barres obliques (séparateurs de chemin), il correspond à zéro ou plusieurs répertoires.
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))
Ceci est une solution Python 3.4+ pathlib
:
exts = ".pdf", ".doc", ".xls", ".csv", ".ppt"
filelist = (str(i) for i in map(pathlib.Path, os.listdir(src)) if i.suffix.lower() in exts and not i.stem.startswith("~"))
En outre, il ignore tous les noms de fichiers commençant par ~
.
Pas glob
, mais voici une autre façon d'utiliser une compréhension de liste:
extensions = 'txt mdown markdown'.split()
projectFiles = [f for f in os.listdir(projectDir)
if os.path.splitext(f)[1][1:] in extensions]
Autant de réponses qui suggèrent de déplacer autant de fois que de fois le nombre d'extensions, je préférerais ne déplacer qu'une seule fois à la place:
from pathlib import Path
files = {p.resolve() for p in Path(path).glob("**/*") if p.suffix in [".c", ".cc", ".cpp", ".hxx", ".h"]}
La fonction suivante _glob
globs pour plusieurs extensions de fichiers.
import glob
import os
def _glob(path, *exts):
"""Glob for multiple file extensions
Parameters
----------
path : str
A file name without extension, or directory name
exts : Tuple
File extensions to glob for
Returns
-------
files : list
list of files matching extensions in exts in path
"""
path = os.path.join(path, "*") if os.path.isdir(path) else path + "*"
return [f for files in [glob.glob(path + ext) for ext in exts] for f in files]
files = _glob(projectDir, ".txt", ".mdown", ".markdown")
J'ai publié Formic qui implémente plusieurs inclus d'une manière similaire à celle d'Apache Ant FileSet and Globs .
La recherche peut être implémentée:
import formic
patterns = ["*.txt", "*.markdown", "*.mdown"]
fileset = formic.FileSet(directory=projectDir, include=patterns)
for file_name in fileset.qualified_files():
# Do something with file_name
Etant donné que Ant glob complet est implémenté, vous pouvez inclure différents répertoires avec chaque modèle. Ainsi, vous ne pouvez choisir que les fichiers .txt d'un sous-répertoire et les fichiers .markdown d'un autre, par exemple:
patterns = [ "/unformatted/**/*.txt", "/formatted/**/*.mdown" ]
J'espère que ça aide.
Pour glob
plusieurs types de fichiers, vous devez appeler glob()
plusieurs fois dans une boucle. Puisque cette fonction retourne une liste, vous devez concaténer les listes.
Par exemple, cette fonction fait le travail:
import glob
import os
def glob_filetypes(root_dir, *patterns):
return [path
for pattern in patterns
for path in glob.glob(os.path.join(root_dir, pattern))]
Utilisation simple:
project_dir = "path/to/project/dir"
for path in sorted(glob_filetypes(project_dir, '*.txt', '*.mdown', '*.markdown')):
print(path)
Vous pouvez aussi utiliser glob.iglob()
pour avoir un itérateur:
Retourne un itérateur qui donne les mêmes valeurs que glob () sans les stocker tous en même temps.
def iglob_filetypes(root_dir, *patterns):
return (path
for pattern in patterns
for path in glob.iglob(os.path.join(root_dir, pattern)))
D'après les résultats des tests empiriques obtenus, il s'est avéré que glob.glob
N'est pas le meilleur moyen de filtrer les fichiers par leurs extensions. Certaines des raisons sont:
J'ai testé (pour l'exactitude et l'efficacité dans le temps) les différentes méthodes suivantes 4
Pour filtrer les fichiers par extension et les mettre dans un list
:
from glob import glob, iglob
from re import compile, findall
from os import walk
def glob_with_storage(args):
elements = ''.join([f'[{i}]' for i in args.extensions])
globs = f'{args.target}/**/*{elements}'
results = glob(globs, recursive=True)
return results
def glob_with_iteration(args):
elements = ''.join([f'[{i}]' for i in args.extensions])
globs = f'{args.target}/**/*{elements}'
results = [i for i in iglob(globs, recursive=True)]
return results
def walk_with_suffixes(args):
results = []
for r, d, f in walk(args.target):
for ff in f:
for e in args.extensions:
if ff.endswith(e):
results.append(path_join(r,ff))
break
return results
def walk_with_regs(args):
reg = compile('|'.join([f'{i}$' for i in args.extensions]))
results = []
for r, d, f in walk(args.target):
for ff in f:
if len(findall(reg,ff)):
results.append(path_join(r, ff))
return results
En exécutant le code ci-dessus sur mon ordinateur portable, j'ai obtenu les résultats auto-explicatifs suivants.
Elapsed time for '7 times glob_with_storage()': 0.365023 seconds.
mean : 0.05214614
median : 0.051861
stdev : 0.001492152
min : 0.050864
max : 0.054853
Elapsed time for '7 times glob_with_iteration()': 0.360037 seconds.
mean : 0.05143386
median : 0.050864
stdev : 0.0007847381
min : 0.050864
max : 0.052859
Elapsed time for '7 times walk_with_suffixes()': 0.26529 seconds.
mean : 0.03789857
median : 0.037899
stdev : 0.0005759071
min : 0.036901
max : 0.038896
Elapsed time for '7 times walk_with_regs()': 0.290223 seconds.
mean : 0.04146043
median : 0.040891
stdev : 0.0007846776
min : 0.04089
max : 0.042885
Results sizes:
0 2451
1 2451
2 2446
3 2446
Differences between glob() and walk():
0 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Includes\numpy
1 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Utility\CppSupport.cpp
2 E:\x\y\z\venv\lib\python3.7\site-packages\future\moves\xmlrpc
3 E:\x\y\z\venv\lib\python3.7\site-packages\Cython\Includes\libcpp
4 E:\x\y\z\venv\lib\python3.7\site-packages\future\backports\xmlrpc
Elapsed time for 'main': 1.317424 seconds.
Le moyen le plus rapide de filtrer les fichiers par extension est même le plus laid. Ce qui est imbriqué des boucles for
et de la comparaison string
en utilisant la méthode endswith()
.
De plus, comme vous pouvez le constater, les algorithmes de déplacement (avec le motif E:\x\y\z\**/*[py][pyc]
), Même avec l’extension 2
Uniquement (py
et pyc
), sont également incorrects. résultats.
Vous pouvez essayer de faire une liste manuelle en comparant l’extension de l’existant avec celles dont vous avez besoin.
ext_list = ['gif','jpg','jpeg','png'];
file_list = []
for file in glob.glob('*.*'):
if file.rsplit('.',1)[1] in ext_list :
file_list.append(file)
Un glob, plusieurs extensions ... mais solution imparfaite (peut correspondre à d'autres fichiers).
filetypes = ['tif', 'jpg']
filetypes = Zip(*[list(ft) for ft in filetypes])
filetypes = ["".join(ch) for ch in filetypes]
filetypes = ["[%s]" % ch for ch in filetypes]
filetypes = "".join(filetypes) + "*"
print(filetypes)
# => [tj][ip][fg]*
glob.glob("/path/to/*.%s" % filetypes)
Vous pouvez aussi utiliser reduce()
comme ceci:
import glob
file_types = ['*.txt', '*.mdown', '*.markdown']
project_files = reduce(lambda list1, list2: list1 + list2, (glob.glob(t) for t in file_types))
cela crée une liste de glob.glob()
pour chaque modèle et les réduit à une seule liste.
Utilisez une liste d’extensions et parcourez-les
from os.path import join
from glob import glob
files = ['*.gif', '*.png', '*.jpg']
for ext in files:
files.extend(glob(join("path/to/dir", ext)))
print(files)
import os
import glob
import operator
from functools import reduce
types = ('*.jpg', '*.png', '*.jpeg')
lazy_paths = (glob.glob(os.path.join('my_path', t)) for t in types)
paths = reduce(operator.add, lazy_paths, [])
https://docs.python.org/3.5/library/functools.html#functools.reducehttps://docs.python.org/3.5/library/operator.html# operator.add
Vous pouvez utiliser le filtre:
import os
import glob
projectFiles = filter(
lambda x: os.path.splitext(x)[1] in [".txt", ".mdown", ".markdown"]
glob.glob(os.path.join(projectDir, "*"))
)
Encore une autre solution (utilisez glob
pour obtenir les chemins utilisant plusieurs correspondances patterns
et combinez tous les chemins en une liste unique en utilisant reduce
et add
):
import functools, glob, operator
paths = functools.reduce(operator.add, [glob.glob(pattern) for pattern in [
"path1/*.ext1",
"path2/*.ext2"]])
Si vous utilisez pathlib
essayez ceci:
import pathlib
extensions = ['.py', '.txt']
root_dir = './test/'
files = filter(lambda p: p.suffix in extensions, pathlib.Path(root_dir).glob('**/*'))
print(list(files))
J'ai eu le même problème et c'est ce que je suis venu avec
import os, sys, re
#without glob
src_dir = '/mnt/mypics/'
src_pics = []
ext = re.compile('.*\.(|{}|)$'.format('|'.join(['png', 'jpeg', 'jpg']).encode('utf-8')))
for root, dirnames, filenames in os.walk(src_dir):
for filename in filter(lambda name:ext.search(name),filenames):
src_pics.append(os.path.join(root, filename))
Par exemple:
import glob
lst_img = []
base_dir = '/home/xy/img/'
# get all the jpg file in base_dir
lst_img += glob.glob(base_dir + '*.jpg')
print lst_img
# ['/home/xy/img/2.jpg', '/home/xy/img/1.jpg']
# append all the png file in base_dir to lst_img
lst_img += glob.glob(base_dir + '*.png')
print lst_img
# ['/home/xy/img/2.jpg', '/home/xy/img/1.jpg', '/home/xy/img/3.png']
Une fonction:
import glob
def get_files(base_dir='/home/xy/img/', lst_extension=['*.jpg', '*.png']):
"""
:param base_dir:base directory
:param lst_extension:lst_extension: list like ['*.jpg', '*.png', ...]
:return:file lists like ['/home/xy/img/2.jpg','/home/xy/img/3.png']
"""
lst_files = []
for ext in lst_extension:
lst_files += glob.glob(base_dir+ext)
return lst_files