Python glob多个文件类型

时间:2010-12-31 06:39:15

标签: python glob

有没有更好的方法在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') )

35 个答案:

答案 0 :(得分:111)

也许有更好的方法,但是如何:

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

也许有另一种方式,所以请等待其他人提出更好的答案。

答案 1 :(得分:38)

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)

答案 2 :(得分:31)

将结果链接起来:

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

答案 3 :(得分:23)

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

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

答案 4 :(得分:15)

使用glob是不可能的。你只能使用:
*匹配所有内容 ?匹配任何单个字符
[seq]匹配seq中的任何字符 [!seq]匹配不在seq中的任何字符

使用os.listdir和regexp来检查模式:

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

答案 5 :(得分:10)

例如,对于多个文件夹中的*.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]*

答案 6 :(得分:6)

虽然Bash的glob之后并没有真正遵循Python的默认glob,但是您可以使用其他库来实现。我们可以在wcmatch's glob中启用花括号。

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

如果您愿意,甚至可以使用extended glob patterns

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

答案 7 :(得分:5)

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

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 的行为密切匹配(请参阅 documentation)。

请注意,使用内置包 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)]

答案 8 :(得分:4)

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

答案 9 :(得分:4)

一个单行,只是为了它的地狱..

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

答案 10 :(得分:3)

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

此外,它会忽略以~开头的所有文件名。

答案 11 :(得分:3)

以下是Pat的答案的单行列表理解变体(其中还包括您希望在特定项目目录中的glob):

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))匹配。

此解决方案 short ,没有任何不必要的for循环,嵌套列表推导或函数来混淆代码。只是纯粹的,富有表现力的,pythonic Zen

此解决方案允许您拥有exts的自定义列表,无需更新代码即可对其进行更改。 (这总是一种很好的做法!)

列表理解与Laurent的解决方案(我已投票选出)相同。但我认为通常不需要将单行分解为单独的函数,这就是为什么我将此作为替代解决方案的原因。

加分:

如果您不仅需要搜索单个目录,还需要搜索所有子目录,则可以传递recursive=True并使用多目录glob符号** 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符号只匹配一个或多个字符,包括forward-slash /(与单数{{1不同) glob符号)。在实践中,您只需要记住,只要用正斜杠(路径分隔符)包围*,它就匹配零个或多个目录。

答案 12 :(得分:2)

不是glob,但这是使用列表理解的另一种方式:

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

答案 13 :(得分:2)

以下函数_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")

答案 14 :(得分:2)

我发布了Formic,它以与Apache Ant FileSet and 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" ]

我希望这会有所帮助。

答案 15 :(得分:2)

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

答案 16 :(得分:1)

太多的答案建议使用扩展名的次数是扩展名的次数,我宁愿只使用一次扩展名:

DataContext

答案 17 :(得分:1)

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

答案 18 :(得分:0)

如果您使用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))

答案 19 :(得分:0)

import os
import glob

projectFiles = [i for i in glob.glob(os.path.join(projectDir,"*")) if os.path.splitext(i)[-1].lower() in ['.txt','.markdown','.mdown']]

os.path.splitext 将返回文件名和 .extension

filename, .extension = os.path.splitext('filename.extension')

.lower() 将字符串转换为小写

答案 20 :(得分:0)

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

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 :(得分:0)

这对我有用!

split('.')[-1]

上面的代码将文件名后缀(*.xxx)分开,以便为您提供帮助

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

答案 22 :(得分:0)

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

这还不算太糟。

答案 23 :(得分:0)

根据先前的答案

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)

答案 24 :(得分:0)

您可以使用过滤器:

import os
import glob

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

答案 25 :(得分:0)

根据我从经验测试获得的结果,事实证明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]2py),通配算法(使用模式pyc)也会返回错误的结果

答案 26 :(得分:0)

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

答案 27 :(得分:0)

另一种解决方案(使用glob使用多个匹配项patterns获取路径,并使用reduceadd将所有路径合并为一个列表):

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

答案 28 :(得分:0)

使用扩展列表并进行遍历

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)

答案 29 :(得分:0)

例如:

<li>

一个功能:

form.valueChanges

答案 30 :(得分:0)

你也可以这样使用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()为每个模式创建一个列表,并将它们缩减为单个列表。

答案 31 :(得分:0)

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

答案 32 :(得分:0)

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

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

答案 33 :(得分:-1)

这应该有效:

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

答案 34 :(得分:-2)

这对我有用:

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