如何使用递归查找文件?

1010
我想要递归列出一个目录中的所有文件。我当前有这样的目录结构:
  • 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'))

但这显然是有限和笨重的,我该如何正确地做到这一点?


在这种情况下 glob('src/**/*.c') 不能工作吗? - Likith Reddy
28个回答

2
那个使用fnmatch或正则表达式:
import fnmatch, os

def filepaths(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            try:
                matched = pattern.match(basename)
            except AttributeError:
                matched = fnmatch.fnmatch(basename, pattern)
            if matched:
                yield os.path.join(root, basename)

# usage
if __name__ == '__main__':
    from pprint import pprint as pp
    import re
    path = r'/Users/hipertracker/app/myapp'
    pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
    pp([x for x in filepaths(path, '*.py')])

2

我刚刚做了这个.. 它会以层次结构的方式打印文件和目录。

但是我没有使用fnmatch或walk函数。

#!/usr/bin/python

import os,glob,sys

def dirlist(path, c = 1):

        for i in glob.glob(os.path.join(path, "*")):
                if os.path.isfile(i):
                        filepath, filename = os.path.split(i)
                        print '----' *c + filename

                elif os.path.isdir(i):
                        dirname = os.path.basename(i)
                        print '----' *c + dirname
                        c+=1
                        dirlist(i,c)
                        c-=1


path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)

1

以下是使用列表推导式在目录及其所有子目录中递归搜索多个文件扩展名的解决方案:

import os, glob

def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions 
    Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
    with .jpg and .JPG

    Parameters
    ----------
    path : str
        A directory name
    exts : tuple
        File extensions to glob for

    Returns
    -------
    files : list
        list of files matching extensions in exts in path and subfolders

    """
    dirs = [a[0] for a in os.walk(path)]
    f_filter = [d+e for d in dirs for e in exts]    
    return [f for files in [glob.iglob(files) for files in f_filter] for f in files]

my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
    print f

1

这是Johan Dahlin的答案的简化版本,没有fnmatch

import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']

0

这里有一个解决方案,它将模式与完整路径匹配,而不仅仅是基本文件名。

它使用 fnmatch.translate 将 glob 样式的模式转换为正则表达式,然后将其与在遍历目录时找到的每个文件的完整路径进行匹配。

re.IGNORECASE 是可选的,但在 Windows 上很理想,因为文件系统本身不区分大小写。(我没有编译正则表达式,因为文档表明它应该在内部缓存。)

import fnmatch
import os
import re

def findfiles(dir, pattern):
    patternregex = fnmatch.translate(pattern)
    for root, dirs, files in os.walk(dir):
        for basename in files:
            filename = os.path.join(root, basename)
            if re.search(patternregex, filename, re.IGNORECASE):
                yield filename

0

我修改了这篇文章中的顶部答案,并最近创建了这个脚本,它将循环遍历给定目录(searchdir)中的所有文件和其子目录...并打印文件名、根目录、修改/创建日期和大小。

希望这能帮助到某些人...他们可以遍历目录并获取文件信息。

import time
import fnmatch
import os

def fileinfo(file):
    filename = os.path.basename(file)
    rootdir = os.path.dirname(file)
    lastmod = time.ctime(os.path.getmtime(file))
    creation = time.ctime(os.path.getctime(file))
    filesize = os.path.getsize(file)

    print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize)

searchdir = r'D:\Your\Directory\Root'
matches = []

for root, dirnames, filenames in os.walk(searchdir):
    ##  for filename in fnmatch.filter(filenames, '*.c'):
    for filename in filenames:
        ##      matches.append(os.path.join(root, filename))
        ##print matches
        fileinfo(os.path.join(root, filename))

0
import sys, os, glob

dir_list = ["c:\\books\\heap"]

while len(dir_list) > 0:
    cur_dir = dir_list[0]
    del dir_list[0]
    list_of_files = glob.glob(cur_dir+'\\*')
    for book in list_of_files:
        if os.path.isfile(book):
            print(book)
        else:
            dir_list.append(book)

-1

我需要一个适用于Python 2.x的解决方案,可以在大型目录上快速运行。
最终我得到了这个:

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

请注意,如果ls找不到任何匹配的文件,您可能需要一些异常处理。

我刚刚意识到 ls src/**/*.c 只有在启用 globstar 选项 (shopt -s globstar) 的情况下才能正常工作 - 详情请参见此答案 - Roman
如果你想要快速执行,子进程绝不是一个好的解决方案,而且在脚本中使用 ls 绝对是需要避免的。 - tripleee
好的,我不知道这个。它对我很有效 - 而且只需要不到一秒钟的时间(而不是超过30秒...) - Roman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接