Python Glob mehrere Dateitypen

142

Gibt es eine bessere Möglichkeit, glob.glob in Python zu verwenden, um eine Liste mehrerer Dateitypen wie .txt, .mdown und .markdown abzurufen? Im Moment habe ich so etwas:

projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') )
projectFiles2 = glob.glob( os.path.join(projectDir, '*.mdown') )
projectFiles3 = glob.glob( os.path.join(projectDir, '*.markdown') )
Raptrex
quelle
1
Sehr bezogen werden : stackoverflow.com/q/48181073/880783
Bers

Antworten:

156

Vielleicht gibt es einen besseren Weg, aber wie wäre es mit:

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

Vielleicht gibt es einen anderen Weg, also warten Sie, falls jemand anderes eine bessere Antwort findet.

user225312
quelle
19
files_grabbed = [glob.glob(e) for e in ['*.pdf', '*.cpp']]
Novitoll
10
Die Lösung von Novitoll ist kurz, führt jedoch dazu, dass verschachtelte Listen erstellt werden.
Robroc
9
das kannst du immer machen;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG
1
files_grabbed = [ glob.glob (e) für e in [' .pdf', '* .cpp']]
florisla
3
Dies durchläuft die Liste der Dateien zweimal. In der ersten Iteration wird nach * .pdf und in der zweiten nach * .cpp gesucht. Gibt es eine Möglichkeit, dies in einer Iteration zu erledigen? Überprüfen Sie den kombinierten Zustand jedes Mal?
Ridhuvarshan
47
from glob import glob

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

print(files)

Wenn Sie einen Pfad angeben müssen, durchlaufen Sie Übereinstimmungsmuster und lassen Sie den Join der Einfachheit halber in der Schleife:

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)
user2363986
quelle
44

glob Gibt eine Liste zurück: Warum nicht einfach mehrmals ausführen und die Ergebnisse verketten?

from glob import glob
ProjectFiles = glob('*.txt') + glob('*.mdown') + glob('*markdown')
Patrick-Mooney
quelle
2
Dies ist möglicherweise die am besten lesbare Lösung. Ich würde den Fall ändern ProjectFileszu projectFiles, aber große Lösung.
Hans Goldman
40

Verketten Sie die Ergebnisse:

import itertools as it, glob

def multiple_file_types(*patterns):
    return it.chain.from_iterable(glob.iglob(pattern) for pattern in patterns)

Dann:

for filename in multiple_file_types("*.txt", "*.sql", "*.log"):
    # do stuff
tzot
quelle
13
glob.glob -> glob.iglob, so dass die Iteratorkette vollständig faul ausgewertet wird
rodrigob
1
Ich fand die gleiche Lösung, wusste aber nichts davon chain.from_iterable. Das ist also ähnlich, aber weniger lesbar : it.chain(*(glob.iglob(pattern) for pattern in patterns)).
Florida
17

So viele Antworten, die darauf hindeuten, dass die Anzahl der Erweiterungen so oft wie die Anzahl der Erweiterungen erhöht wird. Ich würde es vorziehen, stattdessen nur einmal zu globalisieren:

from pathlib import Path

files = {p.resolve() for p in Path(path).glob("**/*") if p.suffix in [".c", ".cc", ".cpp", ".hxx", ".h"]}
BPL
quelle
15

mit glob ist das nicht möglich. Sie können nur verwenden:
* passt alles
? stimmt mit einem einzelnen Zeichen überein
[seq] stimmt mit einem beliebigen Zeichen in seq
überein [! seq] stimmt mit einem beliebigen Zeichen überein, das nicht in seq

Verwenden Sie os.listdir und einen regulären Ausdruck, um Muster zu überprüfen:

for x in os.listdir('.'):
  if re.match('.*\.txt|.*\.sql', x):
    print x
Christian
quelle
10
Beenden Sie
1
Ich mag diesen Ansatz - wenn die Ausdruckskraft von glob nicht stark genug ist, aktualisieren Sie auf ein leistungsfähigeres Regex-System, hacken Sie es nicht mit z. B. itertoolsweil nachfolgende Musteränderungen auch hackig sein müssen (sagen Sie, Sie möchten Groß- und Kleinschreibung zulassen). . Oh, und es könnte sauberer sein zu schreiben'.*\.(txt|sql)'
Metakermit
Gibt es einen Grund, os.listdir ('.') Glob.iglob (' . ') Vorzuziehen ?
Mr.WorshipMe
14

Für *.mp3und *.flacin mehreren Ordnern können Sie beispielsweise Folgendes tun:

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

Die Idee kann auf mehr Dateierweiterungen erweitert werden, aber Sie müssen überprüfen, ob die Kombinationen werden keine andere unerwünschte Dateierweiterung übereinstimmen auf diesen Ordner haben. Also sei vorsichtig damit.

Sie können Folgendes tun, um eine beliebige Liste von Erweiterungen automatisch zu einem einzelnen Glob-Muster zu kombinieren:

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]*
feqwix
quelle
6

Ein Einzeiler, nur zum Teufel ..

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]

Ausgabe:

['C:\\multi_pattern_glob_one_liner\\dummy_txt.txt', 'C:\\multi_pattern_glob_one_liner\\dummy_bat.bat']
Gil-Mor
quelle
4

Nachdem ich hierher gekommen war, um Hilfe zu holen, machte ich meine eigene Lösung und wollte sie teilen. Es basiert auf der Antwort von user2363986, aber ich denke, das ist skalierbarer. Das heißt, wenn Sie 1000 Erweiterungen haben, sieht der Code immer noch etwas elegant aus.

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
Hans Goldman
quelle
Funktioniert bei mir nicht Ich benutzedirectoryPath = "/Users/bla/bla/images_dir*."
NeStack
Ich würde mehr Informationen benötigen, um dies für Sie zu debuggen ... Erhalten Sie eine Ausnahme? Wenn Sie unter Windows arbeiten, sieht dieser Pfad auch nicht so aus, als würde er funktionieren (fehlender Laufwerksbuchstabe).
Hans Goldman
4
files = glob.glob('*.txt')
files.extend(glob.glob('*.dat'))
Derek White
quelle
4
Gute Antworten liefern auch eine Erklärung des Codes und vielleicht sogar einige Ihrer Überlegungen hinter dem Code.
SunSparc
4

Während Pythons Standard-Glob nicht wirklich nach Bashs Glob folgt, können Sie dies mit anderen Bibliotheken tun. Wir können geschweifte Klammern in wcmatchs Glob aktivieren .

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

Sie können sogar erweiterte Glob-Muster verwenden, wenn Sie dies bevorzugen:

from wcmatch import glob
>>> glob.glob('*.@(md|ini)', flags=glob.EXTGLOB)
['LICENSE.md', 'README.md', 'tox.ini']
gesichtsloser Benutzer
quelle
Dies nimmt nicht die recursiveFlagge
Shamoon
@Shamoon Nein, es nimmt die glob.GLOBSTARFlagge
gesichtsloser
3

Ich habe freigegeben Formic die Geräte mehr umfasst in ähnlicher Weise wie Apache Ant FileSet und Globs .

Die Suche kann implementiert werden:

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

Da der vollständige Ant glob implementiert ist, können Sie jedem Muster verschiedene Verzeichnisse hinzufügen, sodass Sie nur die TXT-Dateien in einem Unterverzeichnis und die Markierung in einem anderen auswählen können, zum Beispiel:

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

Ich hoffe das hilft.

Andrew Alcock
quelle
3

Die folgenden Funktionsklumpen _globfür mehrere Dateierweiterungen.

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

Dies ist eine Python 3.4+ pathlibLösung:

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

Außerdem werden alle Dateinamen ignoriert, die mit beginnen ~.

Winand
quelle
3

Hier ist eine einzeilige Listenverständnisvariante von Pats Antwort (die auch beinhaltet, dass Sie in einem bestimmten Projektverzeichnis global arbeiten wollten):

import os, glob
exts = ['*.txt', '*.mdown', '*.markdown']
files = [f for ext in exts for f in glob.glob(os.path.join(project_dir, ext))]

Sie durchlaufen die Erweiterungen ( for ext in exts) und nehmen dann für jede Erweiterung jede Datei, die dem Glob-Muster ( for f in glob.glob(os.path.join(project_dir, ext)) entspricht.

Diese Lösung ist kurz und ohne unnötige for-Schleifen, verschachtelte Listenverständnisse oder Funktionen, die den Code überladen. Nur reines, ausdrucksstarkes, pythonisches Zen .

Mit dieser Lösung können Sie eine benutzerdefinierte Liste extserstellen, die geändert werden kann, ohne dass Sie Ihren Code aktualisieren müssen. (Dies ist immer eine gute Praxis!)

Das Listenverständnis ist das gleiche wie in Laurents Lösung (für die ich gestimmt habe). Aber ich würde argumentieren, dass es normalerweise nicht notwendig ist, eine einzelne Zeile einer separaten Funktion zuzuordnen, weshalb ich dies als alternative Lösung anbiete.

Bonus:

Wenn Sie nicht nur ein einzelnes Verzeichnis, sondern auch alle Unterverzeichnisse durchsuchen müssen, können Sie recursive=Truedas Glob-Symbol ** 1 für mehrere Verzeichnisse übergeben und verwenden :

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

Dies wird glob.glob('<project_dir>/**/*.txt', recursive=True)für jede Erweiterung usw. aufgerufen.

1 Technisch gesehen entspricht das **Glob-Symbol einfach einem oder mehreren Zeichen einschließlich Schrägstrich / (im Gegensatz zum singulären *Glob-Symbol). In der Praxis müssen Sie sich nur daran erinnern, dass **es mit null oder mehr Verzeichnissen übereinstimmt , solange Sie mit Schrägstrichen (Pfadtrennzeichen) umgeben.

scholer
quelle
2

Nicht glob, aber hier ist eine andere Möglichkeit, ein Listenverständnis zu verwenden:

extensions = 'txt mdown markdown'.split()
projectFiles = [f for f in os.listdir(projectDir) 
                  if os.path.splitext(f)[1][1:] in extensions]
Joemaller
quelle
1

Sie können versuchen, eine manuelle Liste zu erstellen, in der die vorhandene Erweiterung mit den von Ihnen benötigten erweitert wird.

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)
thegauraw
quelle
1

Bei globmehreren Dateitypen müssen Sie die glob()Funktion mehrmals in einer Schleife aufrufen . Da diese Funktion eine Liste zurückgibt, müssen Sie die Listen verketten.

Zum Beispiel erledigt diese Funktion die Aufgabe:

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

Einfache Verwendung:

project_dir = "path/to/project/dir"
for path in sorted(glob_filetypes(project_dir, '*.txt', '*.mdown', '*.markdown')):
    print(path)

Sie können auch glob.iglob()einen Iterator verwenden:

Geben Sie einen Iterator zurück, der dieselben Werte wie glob () liefert, ohne alle gleichzeitig zu speichern.

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

Verwenden Sie eine Liste mit Erweiterungen und durchlaufen Sie diese

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

Sie könnten Filter verwenden:

import os
import glob

projectFiles = filter(
    lambda x: os.path.splitext(x)[1] in [".txt", ".mdown", ".markdown"]
    glob.glob(os.path.join(projectDir, "*"))
)
LK__
quelle
0

Sie könnten auch reduce()so verwenden:

import glob
file_types = ['*.txt', '*.mdown', '*.markdown']
project_files = reduce(lambda list1, list2: list1 + list2, (glob.glob(t) for t in file_types))

Dadurch wird glob.glob()für jedes Muster eine Liste erstellt und auf eine einzelne Liste reduziert.

cyht
quelle
0

Ein Glob, viele Erweiterungen ... aber unvollständige Lösung (könnte mit anderen Dateien übereinstimmen).

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)
Colllin
quelle
0

Ich hatte das gleiche Problem und das habe ich mir ausgedacht

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

Noch eine andere Lösung (verwenden Sie globdiese Option, um Pfade mit mehreren Übereinstimmungen patternsabzurufen und alle Pfade mit reduceund zu einer einzigen Liste zu kombinieren add):

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

Wenn Sie verwenden, pathlibversuchen Sie Folgendes:

import pathlib

extensions = ['.py', '.txt']
root_dir = './test/'

files = filter(lambda p: p.suffix in extensions, pathlib.Path(root_dir).glob('**/*'))

print(list(files))
qik
quelle
0

Durch die Ergebnisse, die ich aus empirischen Tests erhalten habe, stellte sich heraus, dass dies glob.globnicht der bessere Weg ist, Dateien nach ihren Erweiterungen herauszufiltern. Einige der Gründe sind:

  • Die globbing " Sprache " erlaubt keine perfekte Spezifikation der Mehrfacherweiterung.
  • Der erstere Punkt führt dazu, dass abhängig von den Dateierweiterungen falsche Ergebnisse erzielt werden.
  • Es ist empirisch erwiesen, dass die Globbing-Methode langsamer ist als die meisten anderen Methoden.
  • Auch wenn es seltsam ist, können auch andere Dateisystemobjekte " Erweiterungen " haben, auch Ordner.

Ich habe (auf Richtigkeit und Effizienz in der Zeit) die folgenden 4verschiedenen Methoden getestet , um Dateien nach Erweiterungen herauszufiltern und sie in eine zu setzen 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

Durch Ausführen des obigen Codes auf meinem Laptop habe ich die folgenden automatisch erklärenden Ergebnisse erhalten.

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.

Der schnellste Weg, Dateien nach Erweiterungen herauszufiltern, ist sogar der hässlichste. Das heißt, verschachtelte forSchleifen und stringVergleich mit der endswith()Methode.

Darüber hinaus liefern, wie Sie sehen können, die Globbing-Algorithmen (mit dem Muster E:\x\y\z\**/*[py][pyc]) auch bei nur 2gegebener Erweiterung ( pyund pyc) auch falsche Ergebnisse.

Giova
quelle
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)
Sway Wu
quelle
Hallo Sway Wu, willkommen. Bitte fügen Sie eine Erklärung hinzu.
Tiago Martins Peres 20
-1

Das sollte funktionieren:

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

Beispielsweise:

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

Eine Funktion:

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