web-dev-qa-db-fra.com

Python glob les types de fichiers multiples

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') )
110
Raptrex

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.

122
user225312
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)
39
user2363986

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
34
tzot

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')
26
patrick-mooney

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
15
Christian

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]*
10
feqwix

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']
5
Gil-Mor

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
4
Hans Goldman

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.

3
scholer
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))
3
Derek White

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 ~.

3
Winand

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]
2
joemaller

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"]}
2
BPL

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")
2
Tim Fuller

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.

2
Andrew Alcock

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)))
1
Laurent LAPORTE

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:

  • Le globbing "language" ne permet pas une spécification parfaite de l'extension multiple.
  • Le premier point aboutit à l’obtention de résultats incorrects en fonction des extensions de fichier.
  • Il a été prouvé empiriquement que la méthode de globbing était plus lente que la plupart des autres méthodes.
  • Même si c'est étrange, même les autres objets du système de fichiers peuvent avoir des dossiers "extensions".

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.

0
Giova

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

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

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.

0
cyht

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)
0
Projesh Bhoumik
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

0
unpangloss

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, "*"))
)
0
LK__

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"]])
0
Petr Vepřek

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

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

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
0
Jayhello