Python glob plusieurs types de fichiers


142

Existe-t-il un meilleur moyen d'utiliser glob.glob en 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') )

Réponses:


156

Il existe peut-être un meilleur moyen, mais qu'en est-il:

import glob
types = ('*.pdf', '*.cpp') # the tuple of file types
files_grabbed = []
for files in types:
    files_grabbed.extend(glob.glob(files))

# files_grabbed is the list of pdf and cpp files

Il y a peut-être un autre moyen, alors attendez au cas où quelqu'un d'autre trouverait une meilleure réponse.


19
files_grabbed = [glob.glob(e) for e in ['*.pdf', '*.cpp']]
Novitoll

10
La solution de Novitoll est courte, mais elle finit par créer des listes imbriquées.
robroc

9
vous pouvez toujours le faire;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG

1
files_grabbed = [ glob.glob (e) pour e dans [' .pdf', '* .cpp']]
florisla

3
Cela parcourt deux fois la liste des fichiers. Dans la première itération, il vérifie * .pdf et dans la seconde, il vérifie * .cpp. Existe-t-il un moyen de le faire en une seule itération? Vérifiez la condition combinée à chaque fois?
Ridhuvarshan

47
from glob import glob

files = glob('*.gif')
files.extend(glob('*.png'))
files.extend(glob('*.jpg'))

print(files)

Si vous avez besoin de spécifier un chemin, faites une boucle sur les modèles de correspondance 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)

45

glob renvoie une liste: pourquoi ne pas l'exécuter plusieurs fois et concaténer les résultats?

from glob import glob
project_files = glob('*.txt') + glob('*.mdown') + glob('*.markdown')

3
C'est probablement la solution la plus lisible donnée. Je changerais le cas de ProjectFilesla projectFiles, mais une grande solution.
Hans Goldman

40

Chaîne 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

13
glob.glob -> glob.iglob pour que la chaîne d'itérateurs soit entièrement évaluée paresseusement
rodrigob

1
J'ai trouvé la même solution mais je n'en savais rien chain.from_iterable. Donc , ce qui est similaire, mais moins lisible: it.chain(*(glob.iglob(pattern) for pattern in patterns)).
florisla

17

Autant de réponses qui suggèrent de glober autant de fois que de nombre d'extensions, je préférerais glober 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"]}

15

avec glob ce n'est pas possible. vous ne pouvez utiliser que:
* correspond à tout
? correspond à n'importe quel caractère unique
[seq] correspond à n'importe quel caractère de seq
[! seq] correspond à tout caractère ne figurant pas dans seq

utilisez os.listdir et une expression régulière pour vérifier les modèles:

for x in os.listdir('.'):
  if re.match('.*\.txt|.*\.sql', x):
    print x

10
terminez votre expression régulière avec $ pour ne correspondre qu'à la fin des noms de fichiers
ThiefMaster

1
J'aime cette approche - si l'expressivité de glob n'est pas assez puissante, passez à un système regex plus puissant, ne le piratez pas en utilisant, par exemple, itertoolsparce que les changements de modèle ultérieurs doivent également être piratés (disons que vous voulez autoriser les majuscules et les minuscules) . Oh, et il pourrait être plus propre d'écrire'.*\.(txt|sql)'
metakermit

Y a-t-il une raison de préférer os.listdir ('.') À glob.iglob (' . ')?
Mr.WorshipMe

14

Par exemple, pour *.mp3et *.flacsur plusieurs dossiers, vous pouvez faire:

mask = r'music/*/*.[mf][pl][3a]*'
glob.glob(mask)

L'idée peut être étendue à plus d'extensions de fichiers, mais vous devez vérifier que les combinaisons ne correspondent à aucune autre extension de fichier indésirable que vous pourriez avoir sur ces dossiers. Alors, soyez prudent avec cela.

Pour combiner automatiquement une liste arbitraire d'extensions en un seul modèle global, vous pouvez effectuer les opérations suivantes:

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

6

Un one-liner, juste pour le plaisir.

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]

production:

['C:\\multi_pattern_glob_one_liner\\dummy_txt.txt', 'C:\\multi_pattern_glob_one_liner\\dummy_bat.bat']

4

Après être venu ici pour obtenir de l'aide, j'ai créé ma propre solution et je voulais la partager. Il 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 sera toujours un peu é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

Ça ne marche pas pour moi. J'utilisedirectoryPath = "/Users/bla/bla/images_dir*."
NeStack

J'aurais besoin de plus d'informations pour déboguer cela pour vous ... Obtenez-vous une exception? De plus, si vous êtes sous Windows, ce chemin ne semble pas fonctionner (lettre de lecteur manquante).
Hans Goldman

4
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))

4
Les bonnes réponses fournissent également des explications sur le code et peut-être même une partie de votre raisonnement derrière le code.
SunSparc

4

Bien que le glob par défaut de Python ne suive pas vraiment le glob de Bash, vous pouvez le faire avec d'autres bibliothèques. Nous pouvons activer les accolades dans le glob de wcmatch .

>>> from wcmatch import glob
>>> glob.glob('*.{md,ini}', flags=glob.BRACE)
['LICENSE.md', 'README.md', 'tox.ini']

Vous pouvez même utiliser des modèles globaux étendus si tel est votre préférence:

from wcmatch import glob
>>> glob.glob('*.@(md|ini)', flags=glob.EXTGLOB)
['LICENSE.md', 'README.md', 'tox.ini']

Cela ne prend pas le recursivedrapeau
Shamoon

@Shamoon Non, il prend le glob.GLOBSTARdrapeau
facelessuser

3

J'ai publié Formic qui implémente plusieurs inclusions d' une manière similaire à FileSet et Globs d'Apache Ant .

La recherche peut être mise en œuvre:

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

Étant donné que le glob Ant complet est implémenté, vous pouvez inclure différents répertoires avec chaque modèle, vous pouvez donc choisir uniquement ces fichiers .txt dans un sous-répertoire et le .markdown dans un autre, par exemple:

patterns = [ "/unformatted/**/*.txt", "/formatted/**/*.mdown" ]

J'espère que ça aide.


3

La fonction suivante _globregroupe plusieurs extensions de fichier.

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

3

Ceci est une pathlibsolution Python 3.4+ :

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("~"))

De plus, il ignore tous les noms de fichiers commençant par ~.


3

Voici une variante de compréhension de liste en une ligne de la réponse de Pat (qui comprend également que vous vouliez glober 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 bouclez sur les extensions ( for ext in exts), puis pour chaque extension, vous prenez chaque fichier correspondant au modèle global ( for f in glob.glob(os.path.join(project_dir, ext)).

Cette solution est courte et sans boucles for inutiles, compréhensions de listes imbriquées ou fonctions pour encombrer le code. Un Zen pur, expressif et pythonique .

Cette solution vous permet d'avoir une liste personnalisée de ceux extsqui peuvent être modifiés sans avoir à mettre à jour votre code. (C'est toujours une bonne pratique!)

La liste-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 est généralement inutile de factoriser une seule ligne vers une fonction distincte, c'est pourquoi je propose cela comme une solution alternative.

Prime:

Si vous avez besoin de rechercher non seulement un seul répertoire, mais également tous les sous-répertoires, vous pouvez passer recursive=Trueet utiliser le symbole glob multi-répertoires ** 1 :

files = [f for ext in exts 
         for f in glob.glob(os.path.join(project_dir, '**', ext), recursive=True)]

Cela 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 *symbole glob singulier ). En pratique, vous devez simplement vous rappeler que tant que vous entourez **de barres obliques (séparateurs de chemin), cela correspond à zéro ou plusieurs répertoires.


2

Non 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]

1

Vous pouvez essayer de faire une liste manuelle comparant l'extension de l'existant avec ceux 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)


1

Pour globplusieurs types de fichiers, vous devez appeler la glob()fonction plusieurs fois dans une boucle. Puisque cette fonction renvoie 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 également utiliser glob.iglob()pour avoir un itérateur:

Renvoie un itérateur qui donne les mêmes valeurs que glob () sans les stocker toutes simultanément.

def iglob_filetypes(root_dir, *patterns):
    return (path
            for pattern in patterns
            for path in glob.iglob(os.path.join(root_dir, pattern)))

1

Utilisez une liste d'extensions et parcourez

from os.path import join
from glob import glob

files = []
extensions = ['*.gif', '*.png', '*.jpg']
for ext in extensions:
   files.extend(glob(join("path/to/dir", ext)))

print(files)

0

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

Vous pouvez également 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 à partir de glob.glob()pour chaque modèle et les réduit à une seule liste.


0

Un glob, de nombreuses extensions ... mais une 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

J'ai eu le même problème et c'est ce que j'ai trouvé

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

Encore une autre solution (utiliser globpour obtenir des chemins en utilisant plusieurs correspondances patternset combiner tous les chemins en une seule liste en utilisant reduceet add):

import functools, glob, operator
paths = functools.reduce(operator.add, [glob.glob(pattern) for pattern in [
    "path1/*.ext1",
    "path2/*.ext2"]])

0

Si vous utilisez, pathlibessayez 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

D'après les résultats que j'ai obtenus à partir de tests empiriques, il s'est avéré que ce glob.globn'était pas la meilleure façon de filtrer les fichiers par leurs extensions. Certaines des raisons sont:

  • Le « langage » globbing ne permet pas une spécification parfaite d'extensions multiples.
  • Le premier point entraîne l'obtention de résultats incorrects en fonction des extensions de fichiers.
  • Il a été prouvé empiriquement que la méthode de globbing est plus lente que la plupart des autres méthodes.
  • Même si c'est étrange, même d'autres objets de système de fichiers peuvent avoir des " extensions ", des dossiers aussi.

J'ai testé (pour l'exactitude et l'efficacité dans le temps) les 4différentes méthodes suivantes pour filtrer les fichiers par extensions 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 extensions est même le plus laid. Autrement dit, forboucles imbriquées et stringcomparaison à l'aide de la endswith()méthode.

De plus, comme vous pouvez le voir, les algorithmes de globbing (avec le modèle E:\x\y\z\**/*[py][pyc]) même avec seulement l' 2extension donnée ( pyet pyc) retournent également des résultats incorrects.


0
import glob
import pandas as pd

df1 = pd.DataFrame(columns=['A'])
for i in glob.glob('C:\dir\path\*.txt'):
    df1 = df1.append({'A': i}, ignore_index=True)
for i in glob.glob('C:\dir\path\*.mdown'):
    df1 = df1.append({'A': i}, ignore_index=True)
for i in glob.glob('C:\dir\path\*.markdown):
    df1 = df1.append({'A': i}, ignore_index=True)

Salut Sway Wu, bienvenue. Pensez à ajouter une explication.
Tiago Martins Peres 李大仁

-1

Cela devrait fonctionner:

import glob
extensions = ('*.txt', '*.mdown', '*.markdown')
for i in extensions:
    for files in glob.glob(i):
        print (files)

-1

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.