如何递归查找文件?

1026 投票
28 回答
1068768 浏览
提问于 2025-04-15 18:47

我想要在一个文件夹里递归地列出所有文件。现在我的文件夹结构是这样的:

  • src/main.c
  • src/dir/file1.c
  • src/another-dir/file2.c
  • src/another-dir/nested/files/file3.c

我试过这样做:

from glob import glob

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

但是这样只能获取到src子文件夹下直接的文件,比如我能得到main.c,但却得不到file1.cfile2.c等文件。

from glob import glob

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

显然,这种方法有限且不够灵活,那我该怎么做才能正确地列出所有文件呢?

28 个回答

123

这个方法和其他解决方案类似,不过它用的是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

另外,使用生成器可以让你在找到每个文件时就处理它,而不是先找到所有文件,然后再处理它们。

215

对于 Python 版本大于等于 3.5 的情况,你可以使用 **recursive=True,也就是说:

import glob
for f in glob.glob('/path/**/*.c', recursive=True):
    print(f)

如果 recursive 设置为 True(默认是 False),那么模式 ** 会匹配任何文件以及零个或多个 目录子目录。如果这个模式后面跟着一个 os.sep,那么只会匹配目录和 子目录


Python 3 示例

1803

有几种方法可以做到这一点:

pathlib.Path().rglob()

可以使用来自pathlib模块的pathlib.Path().rglob(),这个模块是在Python 3.5中引入的。

from pathlib import Path

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

glob.glob()

如果你不想使用pathlib,可以使用glob.glob()

from glob import glob

for filename in glob('src/**/*.c', recursive=True):
    print(filename)   

如果你需要匹配以点(.)开头的文件,比如当前目录中的文件或Unix系统中的隐藏文件,可以使用下面的os.walk()解决方案。

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

这个版本在处理大量文件时可能会更快,因为pathlib模块相对于os.walk()来说有一些额外的开销。

撰写回答