协慌网

登录 贡献 社区

如何使用 glob()递归查找文件?

这就是我所拥有的:

glob(os.path.join('src','*.c'))

但我想搜索 src 的子文件夹。这样的事情会起作用:

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

但这显然是有限且笨拙的。

答案

pathlib.Path.rglob

使用pathlib.Path.rglob模块中的pathlib ,该模块是 Python 3.5 中引入的。

from pathlib import Path

for path in Path('src').rglob('*.c'):
    print(path.name)

如果您不想使用 pathlib,则可以使用glob.glob('**/*.c') ,但是不要忘记传递recursive关键字参数,它将在大型目录上花费大量时间。

对于匹配文件以点( . )开头的情况;例如当前目录中的文件或基于 Unix 的系统上的隐藏文件,请使用os.walk解决方案。

步行

对于较旧的 Python 版本,请使用os.walk递归遍历目录,并使用fnmatch.filter与一个简单表达式进行匹配:

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
    for filename in fnmatch.filter(filenames, '*.c'):
        matches.append(os.path.join(root, filename))

与其他解决方案类似,但是使用 fnmatch.fnmatch 而不是 glob,因为 os.walk 已经列出了文件名:

import os, fnmatch


def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename


for filename in find_files('src', '*.c'):
    print 'Found C source:', filename

另外,使用生成器使您可以处理找到的每个文件,而不是查找所有文件然后进行处理。

我修改了 glob 模块,以支持 ** 用于递归 glob,例如:

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/

当您想为用户提供使用 ** 语法的功能时很有用,因此仅 os.walk()不够好。