Python glob 多个文件类型

2025-02-18 09:25:00
admin
原创
72
摘要:问题描述:有没有更好的方法在 python 中使用 glob.glob 来获取多种文件类型(如 .txt、.mdown 和 .markdown)的列表?现在我有这样的事情:projectFiles1 = glob.glob( os.path.join(projectDir, '*.txt') ) projec...

问题描述:

有没有更好的方法在 python 中使用 glob.glob 来获取多种文件类型(如 .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 is the list of pdf and cpp files

也许还有其他方法,所以请等待,看看是否有人能找到更好的答案。

解决方案 2:

glob返回一个列表:为什么不多次运行它并连接结果?

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

解决方案 3:

很多答案都建议将扩展名的次数进行多次匹配,但我更喜欢只进行一次匹配:

from pathlib import Path

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

解决方案 4:

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)

解决方案 5:

链接结果:

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

解决方案 6:

例如,对于*.mp3多个*.flac文件夹,您可以执行以下操作:

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

这个想法可以扩展到更多文件扩展名,您必须检查这些组合是否与您在这些文件夹中可能拥有的任何其他不需要的文件扩展名相匹配。所以,请小心谨慎

要将任意扩展列表自动组合成单个 glob 模式,您可以执行以下操作:

def multi_extension_glob_mask(mask_base, *extensions):
    mask_ext = ['[{}]'.format(''.join(set(c))) for c in zip(*extensions)]
    if not mask_ext or len(set(len(e) for e in extensions)) > 1:
        mask_ext.append('*')
    return mask_base + ''.join(mask_ext)

mask = multi_extension_glob_mask('music/*/*.', 'mp3', 'flac', 'wma')
print(mask)  # music/*/*.[mfw][pml][a3]*

解决方案 7:

使用 glob 则无法实现。你只能使用:

  • 匹配所有内容

? 匹配任何单个字符

[seq] 匹配 seq 中的任何字符

[!seq] 匹配 seq 之外的任何字符

使用 os.listdir 和正则表达式来检查模式:

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

解决方案 8:

虽然 Python 的默认 glob 并不真正遵循 Bash 的 glob,但您可以使用其他库来做到这一点。我们可以在wcmatch 的 glob中启用括号。

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

如果您愿意,甚至可以使用扩展的 glob 模式:

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

解决方案 9:

与@BPL 的答案相同(计算效率高),但可以处理任何 glob 模式而不是扩展:

import os
from fnmatch import fnmatch

folder = "path/to/folder/"
patterns = ("*.txt", "*.md", "*.markdown")

files = [f.path for f in os.scandir(folder) if any(fnmatch(f, p) for p in patterns)]

glob此解决方案既高效又方便。它还与(参见文档)的行为非常相似。

请注意,使用内置包会更简单pathlib

from pathlib import Path

folder = Path("/path/to/folder")
patterns = ("*.txt", "*.md", "*.markdown")

files = [f for f in folder.iterdir() if any(f.match(p) for p in patterns)]

解决方案 10:

下面是 Pat 的答案的单行列表理解变体(其中还包括您想要在特定项目目录中进行全局遍历):

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 循环、嵌套列表推导或函数来使代码混乱。只有纯粹、富有表现力、Python 风格的

此解决方案允许您拥有一个自定义列表,exts无需更新代码即可更改该列表。(这始终是一个好的做法!)

列表推导式与 Laurent 的解决方案(我已投票支持)中使用的相同。但我认为,通常没有必要将一行代码分解为单独的函数,这就是我提供此解决方案作为替代解决方案的原因。

奖金:

如果您不仅需要搜索单个目录,还需要搜索所有子目录,则可以传递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从技术上讲,**glob 符号仅匹配一个或多个字符(包括正斜杠 /)(与单数*glob 符号不同)。实际上,你只需要记住,只要**用正斜杠(路径分隔符)包围,它就会匹配零个或多个目录。

解决方案 11:

Python 3

我们可以使用pathlib.glob仍然不支持多个参数的匹配或括号内的匹配(如在 POSIX shell 中),但我们可以轻松filter获得结果。

例如,您可能希望这样做:

# NOT VALID
Path(config_dir).glob("*.{ini,toml}")
# NOR IS
Path(config_dir).glob("*.ini", "*.toml")

可以这样做:

filter(lambda p: p.suffix in {".ini", ".toml"}, Path(config_dir).glob("*"))

这也不算太糟。

解决方案 12:

根据我的经验测试结果,事实证明,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:xyzenvlibpython3.7site-packagesCythonIncludes
umpy
1 E:xyzenvlibpython3.7site-packagesCythonUtilityCppSupport.cpp
2 E:xyzenvlibpython3.7site-packagesuturemovesxmlrpc
3 E:xyzenvlibpython3.7site-packagesCythonIncludeslibcpp
4 E:xyzenvlibpython3.7site-packagesutureackportsxmlrpc

Elapsed time for 'main':  1.317424 seconds.

按照扩展名过滤文件最快的方法,也是最丑陋的方法。即使用该方法进行嵌套for循环和string比较endswith()

此外,如您所见,E:xyz**/*[py][pyc]即使仅2给出扩展名(pypyc),通配符算法(使用模式)也会返回不正确的结果。

解决方案 13:

一句台词,只是为了好玩而已……

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

解决方案 14:

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

解决方案 15:

我已经发布了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" ]

我希望这会有所帮助。

解决方案 16:

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

它还会忽略所有以 开头的文件名~

解决方案 17:

来这里寻求帮助后,我提出了自己的解决方案并想分享它。它基于 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

解决方案 18:

不是glob,但是这里有另一种使用列表推导的方法:

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

解决方案 19:

以下函数_glob用于多个文件扩展名。

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

解决方案 20:

您可以尝试制作一个手动列表,将现有的扩展与您需要的扩展进行比较。

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)

解决方案 21:

来自上一个答案

glob('*.jpg') + glob('*.png')

这是一个较短的例子,

from glob import glob
extensions = ['jpg', 'png'] # to find these filename extensions

# Method 1: loop one by one and extend to the output list
output = []
[output.extend(glob(f'*.{name}')) for name in extensions]
print(output)

# Method 2: even shorter
# loop filename extension to glob() it and flatten it to a list
output = [p for p2 in [glob(f'*.{name}') for name in extensions] for p in p2]
print(output)

解决方案 22:

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.reduce
https://docs.python.org/3.5/library/operator.html#operator.add

解决方案 23:

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

解决方案 24:

一个 glob,多个扩展......但不完美的解决方案(可能与其他文件匹配)。

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)

解决方案 25:

我遇到了同样的问题,这就是我想出的

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

解决方案 26:

使用扩展列表并进行迭代

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)

解决方案 27:

这对我有用!

split('.')[-1]

上面的代码将文件名后缀(*.xxx)分开,这样可以帮助你

    for filename in glob.glob(folder + '*.*'):
        print(folder+filename)
        if  filename.split('.')[-1] != 'tif' and \n            filename.split('.')[-1] != 'tiff' and \n            filename.split('.')[-1] != 'bmp' and \n            filename.split('.')[-1] != 'jpg' and \n            filename.split('.')[-1] != 'jpeg' and \n            filename.split('.')[-1] != 'png':
                continue
        # Your code

解决方案 28:

您可以使用过滤器:

import os
import glob

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

解决方案 29:

你也可以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()为每个模式创建一个列表,并将它们简化为单个列表。

解决方案 30:

还有另一种解决方案(使用glob多个匹配获取路径并使用andpatterns将所有路径组合成一个列表):reduce`add`

import functools, glob, operator
paths = functools.reduce(operator.add, [glob.glob(pattern) for pattern in [
    "path1/*.ext1",
    "path2/*.ext2"]])
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2079  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1459  
  建筑行业正处于数字化转型的关键时期,建筑产品生命周期管理(PLM)系统的实施对于提升项目效率、质量和协同性至关重要。特别是在 2025 年,基于建筑信息模型(BIM)的项目进度优化工具成为众多建筑企业关注的焦点。这些工具不仅能够整合项目全生命周期的数据,还能通过精准的分析和模拟,为项目进度管理提供强大支持。BIM 与建...
plm是什么软件   0  
  PLM系统开发的重要性与现状PLM(产品生命周期管理)系统在现代企业的产品研发、生产与管理过程中扮演着至关重要的角色。它贯穿产品从概念设计到退役的整个生命周期,整合了产品数据、流程以及人员等多方面的资源,极大地提高了企业的协同效率和创新能力。通过PLM系统,企业能够实现产品信息的集中管理与共享,不同部门之间可以实时获取...
国产plm软件   0  
  PLM(产品生命周期管理)系统在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和技术的飞速发展,企业对PLM系统的迭代周期优化需求日益迫切。2025年敏捷认证对项目管理提出了新的要求,其中燃尽图作为一种强大的可视化工具,在PLM系统迭代周期优化中有着广泛且重要的应用。深入探讨这些应用,对于提升企业的项...
plm系统主要干什么的   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用