Python glob несколько типов файлов

Есть ли лучший способ использовать glob.glob в python, чтобы получить список из нескольких типов файлов, таких как .txt,.mdown и .markdown? Прямо сейчас у меня есть что-то вроде этого:

projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') )
projectFiles2 = glob.glob( os.path.join(projectDir, '*.mdown') )
projectFiles3 = glob.glob( os.path.join(projectDir, '*.markdown') )

Ответ 1

Может быть, есть лучший способ, но как насчет:

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

Возможно, есть и другой способ, поэтому подождите, если кто-то другой найдет лучший ответ.

Ответ 2

from glob import glob

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

print(files)

Если вам нужно указать путь, перебрать шаблоны соответствия и сохранить соединение внутри цикла для простоты:

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)

Ответ 3

Цепочка результатов:

import itertools as it, glob

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

Тогда:

for filename in multiple_file_types("*.txt", "*.sql", "*.log"):
    # do stuff

Ответ 4

glob возвращает список: почему бы просто не запускать его несколько раз и не конкатенировать результаты?

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

Ответ 5

с glob это невозможно. вы можете использовать только:
* соответствует всем
? соответствует любому одиночному символу
[seq] соответствует любому символу в seq
[! seq] соответствует любому символу не в секундах

используйте os.listdir и regexp для проверки шаблонов:

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

Ответ 6

Например, для *.mp3 и *.flac в нескольких папках вы можете сделать:

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

Идея может быть расширена на большее количество расширений файлов, но вы должны убедиться, что комбинации не будут соответствовать никаким другим нежелательным расширениям файлов, которые могут иметься в этих папках. Так что будьте осторожны с этим.

Чтобы автоматически объединить произвольный список расширений в один шаблон glob, вы можете сделать следующее:

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

Ответ 7

Придя сюда за помощью, я сделал свое собственное решение и хотел поделиться им. Он основан на ответе user2363986, но я думаю, что это более масштабируемо. Это означает, что если у вас 1000 расширений, код будет выглядеть несколько элегантно.

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

Ответ 8

Один лайнер, Только для черта.

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]

выход:

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

Ответ 9

Это решение 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("~"))

Также он игнорирует все имена файлов, начиная с ~.

Ответ 10

Ниже приведен однострочный вариант ответа на вопрос Пата (который также включает в себя то, что вы хотели поместить в определенную директорию проекта):

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

Вы перебираете расширения (for ext in exts), а затем для каждого расширения берете каждый файл, соответствующий шаблону glob (for f in glob.glob(os.path.join(project_dir, ext)).

Это короткое решение без лишних циклов for, вложенных списков и функций, которые не загромождают код. Просто чистый, выразительный, питонический дзен.

Это решение позволяет вам иметь собственный список exts который может быть изменен без обновления вашего кода. (Это всегда хорошая практика!)

Понимание списка такое же, как и в решении Лорана (за которое я голосовал). Но я бы сказал, что обычно нет необходимости выделять одну строку в отдельную функцию, поэтому я предоставляю это в качестве альтернативного решения.

Бонус:

Если вам нужно выполнить поиск не только в одном каталоге, но и во всех подкаталогах, вы можете передать recursive=True и использовать глобальный символ мультикаталога ** 1:

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

Это вызовет glob.glob('<project_dir>/**/*.txt', recursive=True) и так далее для каждого расширения.

1 Технически символ " ** просто соответствует одному или нескольким символам, включая косую черту / (в отличие от единственного символа " *). На практике вам просто нужно помнить, что, пока вы окружаете ** косыми чертами (разделителями пути), оно соответствует нулю или большему количеству каталогов.

Ответ 11

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

Ответ 12

Я выпустил Formic, который реализует несколько включений аналогично Apache Ant FileSet и Globs.

Поиск может быть реализован:

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

Поскольку реализован полный Ant glob, вы можете включать разные каталоги с каждым шаблоном, поэтому вы можете выбирать только те .txt файлы в одном подкаталоге и .markdown в другом, например:

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

Надеюсь, это поможет.

Ответ 13

Не glob, но здесь другой способ использования списка:

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

Ответ 14

Следующая функция _glob globs для нескольких расширений файлов.

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

Ответ 15

В glob несколько типов файлов вам нужно вызвать glob() несколько раз в цикле. Поскольку эта функция возвращает список, вам необходимо объединить списки.

Например, эта функция выполняет задание:

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

Простое использование:

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

Вы также можете использовать glob.iglob(), чтобы иметь итератор:

Возвращает итератор, который дает те же значения, что и glob(), фактически не сохраняя их все одновременно.

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

Ответ 16

Вы можете попытаться составить список вручную, сравнивающий расширение существующего с теми, которые вам нужны.

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)

Ответ 17

Вы можете использовать фильтр:

import os
import glob

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

Ответ 18

Вы также можете использовать reduce() следующим образом:

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

это создает список из glob.glob() для каждого шаблона и сводит их к одному списку.

Ответ 20

Один глобус, много расширений... но несовершенное решение (может совпадать с другими файлами).

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)

Ответ 21

У меня была та же проблема, и это то, что я придумал

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

Ответ 22

Например:

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

Функция:

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

Ответ 23

Используйте список расширений и перебирайте

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)

Ответ 24

Еще одно решение (используйте glob для получения путей, используя несколько patterns совпадения patterns и объединяйте все пути в один список с помощью reduce и add):

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

Ответ 25

Если вы используете pathlib попробуйте это:

import pathlib

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

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

print(list(files))

Ответ 26

По результатам, полученным в результате эмпирических испытаний, оказалось, что glob.glob - не лучший способ отфильтровать файлы по их расширениям. Некоторые из причин:

  • Глобальный "язык" не позволяет точно определить множественное расширение.
  • Первый пункт приводит к получению неверных результатов в зависимости от расширений файлов.
  • Эмпирически доказано, что метод сглаживания медленнее, чем большинство других методов.
  • Даже если это странно, даже объекты других файловых систем могут иметь "расширения", папки тоже.

Я проверил (для корректности и эффективности во времени) следующие 4 различных метода, чтобы отфильтровать файлы по расширениям и поместить их в 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

Запустив код выше на моем ноутбуке, я получил следующие авто-объяснительные результаты.

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.

Самый быстрый способ отфильтровать файлы по расширениям, даже самый уродливый. Который вложен for циклов и сравнения string с помощью endswith().

Более того, как вы можете видеть, алгоритмы сглаживания (с шаблоном E:\x\y\z\**/*[py][pyc]) даже с учетом только 2 заданных расширений (py и pyc) возвращают также неверные результаты.

Ответ 27

Так много ответов, которые предлагают использовать столько же раз, сколько число расширений, я бы предпочел вместо одного:

from pathlib import Path

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

Ответ 28

Это должно работать:

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

Ответ 29

это сработало для меня:

import glob
images = glob.glob('*.JPG' or '*.jpg' or '*.png')