webentwicklung-frage-antwort-db.com.de

Python Glob mehrere Dateitypen

Gibt es eine bessere Möglichkeit, glob.glob in python zu verwenden, um eine Liste mit mehreren Dateitypen wie .txt, .mdown und .markdown abzurufen?

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

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   # the list of pdf and cpp files

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

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

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

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

mit glob ist das nicht möglich. Sie können nur verwenden:
* passt zu allem
? Stimmt mit jedem einzelnen Zeichen überein
[seq] entspricht einem beliebigen Zeichen in seq
[! seq] stimmt mit jedem 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
15
Christian

Zum Beispiel für *.mp3 und *.flac In mehreren Ordnern haben Sie folgende Möglichkeiten:

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

Die Idee kann auf weitere Dateierweiterungen erweitert werden. , aber Sie müssen überprüfen, ob die Kombinationen nicht mit anderen unerwünschten übereinstimmen Dateierweiterung, die Sie möglicherweise für diese Ordner haben. Also, sei vorsichtig damit.

Um eine beliebige Liste von Erweiterungen automatisch zu einem einzigen Glob-Muster zu kombinieren, haben Sie folgende Möglichkeiten:

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

Ein Einzeiler, nur für die Hölle ..

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

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

Hier ist eine einzeilige Variante des Listenverständnisses von Pats Antwort (die auch beinhaltet, dass Sie in einem bestimmten Projektverzeichnis globalisieren 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 entspricht (for f in glob.glob(os.path.join(project_dir, ext)).

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

Mit dieser Lösung können Sie eine benutzerdefinierte Liste von exts erstellen, die geändert werden kann, ohne Ihren Code aktualisieren zu müssen. (Dies ist immer eine gute Übung!)

Das Listenverständnis ist das gleiche wie in Laurent's Lösung (für die ich gestimmt habe). Aber ich würde argumentieren, dass es normalerweise nicht notwendig ist, eine einzelne Zeile in eine separate Funktion zu zerlegen, 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=True Übergeben und das Glob-Symbol für mehrere Verzeichnisse ** Verwenden. 1:

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

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

1 Technisch gesehen entspricht das Glob-Symbol ** Einfach einem oder mehreren Zeichen einschließlich Schrägstrich / (Im Gegensatz zum Singular * Glob-Symbol). In der Praxis müssen Sie sich nur daran erinnern, dass, solange Sie ** Mit Schrägstrichen (Pfadtrennzeichen) umgeben, keine oder mehrere Verzeichnisse übereinstimmen.

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

Dies ist eine Python 3.4+ pathlib Lö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.

3
Winand

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

Bei so vielen Antworten, die darauf hindeuten, so oft wie Erweiterungen zu globen, würde ich es vorziehen, stattdessen nur einmal zu globen:

from pathlib import Path

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

Die folgende Funktion _glob Globs fü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")
2
Tim Fuller

Ich habe Formic veröffentlicht, das mehrere Includes auf ähnliche Weise implementiert wie Apache Ants FileSet und Globs .

Die Suche kann durchgeführt 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 das vollständige Ant-Glob implementiert ist, können Sie in jedes Muster verschiedene Verzeichnisse einfügen, sodass Sie nur die TXT-Dateien in einem Unterverzeichnis und die Markdown-Datei in einem anderen Unterverzeichnis auswählen können. Beispiel:

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

Ich hoffe das hilft.

2
Andrew Alcock

Um glob mehrere Dateitypen zu bearbeiten, müssen Sie glob() 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 Bedienung:

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() verwenden, um einen Iterator zu haben:

Gibt einen Iterator zurück, der die gleichen Werte wie glob () liefert, ohne sie 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)))
1
Laurent LAPORTE

Anhand der Ergebnisse empirischer Tests hat sich herausgestellt, dass glob.glob Nicht der bessere Weg ist, Dateien nach ihren Erweiterungen herauszufiltern. Einige der Gründe sind:

  • Das Globbing "language" erlaubt keine perfekte Angabe von Mehrfacherweiterungen.
  • Der erste Punkt führt dazu, dass je nach Dateierweiterung falsche Ergebnisse erzielt werden.
  • Die Globbing-Methode ist empirisch langsamer 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 4 Verschiedenen Methoden getestet, um Dateien nach Erweiterungen herauszufiltern und sie in ein list zu setzen:

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

Indem ich den obigen Code auf meinem Laptop ausführe, erhalte ich die folgenden automatischen Erklärungsergebnisse.

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 der hässlichste. Das heißt, geschachtelte for Schleifen und string Vergleiche mit der endswith() Methode.

Darüber hinaus, wie Sie sehen können, werden die Globbing-Algorithmen (mit dem Muster E:\x\y\z\**/*[py][pyc]) Auch mit nur der angegebenen 2 - Erweiterung (py und pyc) nicht korrekt zurückgegeben Ergebnisse.

0
Giova

Sie können versuchen, eine manuelle Liste zu erstellen, in der die Erweiterung der vorhandenen mit den von Ihnen gewünschten verglichen 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)
0
thegauraw

Ein Glob, viele Erweiterungen ... aber unvollkommene 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)
0
colllin

Sie könnten auch reduce() wie folgt 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 für jedes Muster eine Liste aus glob.glob() erstellt und auf eine einzige Liste reduziert.

0
cyht

Verwenden Sie eine Liste mit Erweiterungen und durchlaufen Sie diese

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

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

Noch eine andere Lösung (verwenden Sie glob, um Pfade mit mehreren Übereinstimmungen patterns abzurufen und kombinieren Sie alle Pfade mit reduce und add zu einer einzigen Liste):

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

Wenn Sie pathlib verwenden, versuchen 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))
0
qik

Ich hatte das gleiche Problem und das ist es, was ich mir ausgedacht habe

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

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