使用fnmatch.filter按多个可能的文件扩展名筛选文件

时间:2011-03-18 12:09:18

标签: python filesystems

给出以下python代码:

for root, dirs, files in os.walk(directory):
    for filename in fnmatch.filter(files, '*.png'):
        pass

如何过滤多个扩展程序?在这种特殊情况下,我希望所有文件都以* .png,* .gif,* .jpg或* .jpeg结尾。

现在我想出了

for root, dirs, files in os.walk(directory):
    for extension in ['jpg', 'jpeg', 'gif', 'png']:
        for filename in fnmatch.filter(files, '*.' + extension):
            pass

但我觉得它不是很优雅和高效。

有人有更好的主意吗?

10 个答案:

答案 0 :(得分:43)

如果您只需要检查扩展名(即没有其他通配符),为什么不简单地使用基本字符串操作?

for root, dirs, files in os.walk(directory):
    for filename in files:
        if filename.endswith(('.jpg', '.jpeg', '.gif', '.png')):
            pass

答案 1 :(得分:8)

我认为你的代码实际上很好。如果您只想触摸每个文件名一次,请定义自己的过滤功能:

def is_image_file(filename, extensions=['.jpg', '.jpeg', '.gif', '.png']):
    return any(filename.endswith(e) for e in extensions)

for root, dirs, files in os.walk(directory):
    for filename in filter(is_image_file, files):
        pass

答案 2 :(得分:6)

我一直在使用它取得了很大的成功。

import fnmatch
import functools
import itertools
import os

# Remove the annotations if you're not on Python3
def find_files(dir_path: str=None, patterns: [str]=None) -> [str]:
    """
    Returns a generator yielding files matching the given patterns
    :type dir_path: str
    :type patterns: [str]
    :rtype : [str]
    :param dir_path: Directory to search for files/directories under. Defaults to current dir.
    :param patterns: Patterns of files to search for. Defaults to ["*"]. Example: ["*.json", "*.xml"]
    """
    path = dir_path or "."
    path_patterns = patterns or ["*"]

    for root_dir, dir_names, file_names in os.walk(path):
        filter_partial = functools.partial(fnmatch.filter, file_names)

        for file_name in itertools.chain(*map(filter_partial, path_patterns)):
            yield os.path.join(root_dir, file_name)

示例:

for f in find_files(test_directory):
    print(f)

的产率:

.\test.json
.\test.xml
.\test.ini
.\test_helpers.py
.\__init__.py

使用多种模式进行测试:

for f in find_files(test_directory, ["*.xml", "*.json", "*.ini"]):
    print(f)

的产率:

.\test.json
.\test.xml
.\test.ini

答案 3 :(得分:4)

这也不是很优雅,但它有效:

for root, dirs, files in os.walk(directory):
    for filename in fnmatch.filter(files, '*.png') + fnmatch.filter(files, '*.jpg') + fnmatch.filter(files, '*.jpeg') + fnmatch.filter(files, '*.gif'):
        pass

答案 4 :(得分:4)

这可能是一种更好的方式,可能是因为您没有反复拨打+并使用tuple而不是list

for root, dirs, files in os.walk(directory):
    for extension in ('*.jpg', '*.jpeg', '*.gif', '*.png'):
        for filename in fnmatch.filter(files, extension):
            pass

tuple更好,因为您在创建扩展程序后不会修改扩展程序。你只是用来迭代它们。

答案 5 :(得分:1)

请尝试以下操作:

# pattern_list = ['*.jpg', '__.*']
def checkFilepatter(filename, pattern_list):
    for pattern in pattern_list:
        if fnmatch.fnmatch(filename, pattern):
            return True
    return False

答案 6 :(得分:0)

以下是我用来过滤apache日志目录中的文件的内容。 在这里,我排除错误flles

rep_filters = [now.strftime("%Y%m%d")]
def files_filter(liste_fic, filters = rep_filters):
    s = "(fic for fic in liste_fic if fic.find('error') < 0"
    for filter in filters:
        s += " and fic.find('%s') >=0 " % filter
    s += ")"
    return eval(s)

答案 7 :(得分:0)

您可以使用列表推导来检查font是否与my_file中定义的任何文件掩码匹配:

patterns

答案 8 :(得分:0)

在内部,fnmatch 用户使用正则表达式。还有一种方法可以根据 fnmatch 模式生成正则表达式 — fnmatch.translate。这也可能会加快一些速度。

import fnmatch
import os
import re

image_exts = ['jpg', 'jpeg', 'gif', 'png']
image_re = re.compile('|'.join(fnmatch.translate('*.' + e) for e in image_exts))
for root, dirs, files in os.walk(directory):
    for filename in files:
        if image_re.match(filename):
            ...

答案 9 :(得分:0)

最明确的解决办法是:

^\h+$

或者,使用 pathlib,

import os

for root, dirs, files in os.walk(directory):
    for filename in files:
        _, ext = os.path.splitext(filename)
        if ext in ['.jpg', '.jpeg', '.gif', '.png']:
            ...