Python Glob多种文件类型


142

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

Answers:


156

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

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

也许还有另一种方式,所以请耐心等待别人提出更好的答案。


19
files_grabbed = [glob.glob(e) for e in ['*.pdf', '*.cpp']]
Novitoll '16

10
Novitoll的解决方案虽然简短,但最终却创建了嵌套列表。
robroc

9
您总是可以这样做;)[f for f_ in [glob.glob(e) for e in ('*.jpg', '*.mp4')] for f in f_]
AlexG

1
files_grabbed = [ [ .pdf','* .cpp']中e的glob.glob(e) ]
florisla

3
这在文件列表中循环两次。在第一次迭代中,它检查* .pdf,在第二次迭代中,检查* .cpp。有没有办法一次完成它?每次检查合并条件?
Ridhuvarshan

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

44

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

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

2
这可能是给出的最易读的解决方案。我会将的大小写更改ProjectFilesprojectFiles,但这是一个很好的解决方案。
汉斯·戈德曼

40

链接结果:

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

13
glob.glob-> glob.iglob,以便完全延迟评估迭代器链
rodrigob 2013年

1
我找到了相同的解决方案,但不知道chain.from_iterable。因此,这是类似的,但不易阅读:it.chain(*(glob.iglob(pattern) for pattern in patterns))
florisla '18

17

这么多的答案表明扩展的次数是扩展次数的两倍,我宁愿只扩展一次:

from pathlib import Path

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

15

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

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

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

10
用$结束您的正则表达式以仅匹配文件名的末尾
ThiefMaster 2010年

1
我喜欢这种方法-如果glob的表达能力不够强大,请升级到功能更强大的正则表达式系统,不要使用hack,例如,itertools因为随后的模式更改也必须很笨拙(例如,您要允许使用大写和小写) 。哦,这样写可能会更干净'.*\.(txt|sql)'
metakermit 2013年

有什么理由比glob.iglob(' ')更喜欢os.listdir(' ')吗?
Mr.WorshipMe '16

14

例如,对于一个*.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

单线,仅此而已..

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

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

对我不起作用。我使用directoryPath = "/Users/bla/bla/images_dir*."
NeStack

我需要更多信息来为您调试...您是否遇到异常?另外,如果您使用的是Windows,则该路径看起来不可行(缺少驱动器号)。
汉斯·高盛

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

4
好的答案还会提供一些代码说明,甚至可能是您在代码背后的某些推理。
SunSparc

4

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

这不会recursive升旗
Shamoon

@Shamoon不,它需要的glob.GLOBSTAR标志
facelessuser

3

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

我希望这有帮助。


3

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

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

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


3

这是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循环,嵌套列表理解或使代码混乱的功能。纯粹,富有表现力的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从技术上讲,**全局符号仅与一个或多个字符(包括正斜杠) 匹配/(不同于单个*全局符号)。实际上,您只需要记住,只要**用正斜杠(路径分隔符)括起来,它就会匹配零个或多个目录。


2

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

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

1

您可以尝试制作一份手动列表,将现有扩展名和所需扩展名进行比较。

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)


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

1

使用扩展列表并遍历

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)

0

您可以使用过滤器:

import os
import glob

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

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()将为每个模式创建一个列表,并将其减少为一个列表。


0

一个团块,许多扩展名,但解决方案不完善(可能与其他文件匹配)。

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

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

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

然而,另一种解决方案(使用glob来获得使用多匹配路径patterns和所有路径组合成用一个单独的列表reduceadd):

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

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

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]即使仅2给出扩展名(pypyc),globbing算法(具有模式)也返回错误的结果。


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,欢迎您。请考虑添加说明。
Tiago Martins Peres李大仁

-1

这应该工作:

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

-1

例如:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.