32

我正在尝试创建一个实用程序类来遍历目录中的所有文件,包括子目录和子子目录中的文件。我尝试使用发电机,因为发电机很酷;但是,我遇到了障碍。


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            yield grab_files(full_path)
        elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)

当生成器到达一个目录时,它只是简单地生成新生成器的内存位置;它没有给我目录的内容。

如何使生成器产生目录的内容而不是新的生成器?

如果已经有一个简单的库函数可以递归地列出目录结构中的所有文件,请告诉我。我不打算复制库函数。

4

7 回答 7

63

当您可以使用os.walk时,为什么要重新发明轮子

import os
for root, dirs, files in os.walk(path):
    for name in files:
        print os.path.join(root, name)

os.walk 是一个生成器,它通过自上而下或自下而上遍历树来生成目录树中的文件名

于 2009-11-09T01:07:34.333 回答
13

我同意 os.walk 解决方案

出于纯粹的迂腐目的,请尝试迭代生成器对象,而不是直接返回它:


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            for entry in grab_files(full_path):
                yield entry
        elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)
于 2009-11-09T01:43:35.700 回答
11

从 Python 3.4 开始,您可以使用glob()内置 pathlib 模块中的方法:

import pathlib
p = pathlib.Path('.')
list(p.glob('**/*'))    # lists all files recursively
于 2017-04-22T18:45:48.670 回答
10

从 Python 3.4 开始,您可以使用Pathlib模块:

In [48]: def alliter(p):
   ....:     yield p
   ....:     for sub in p.iterdir():
   ....:         if sub.is_dir():
   ....:             yield from alliter(sub)
   ....:         else:
   ....:             yield sub
   ....:             

In [49]: g = alliter(pathlib.Path("."))                                                                                                                                                              

In [50]: [next(g) for _ in range(10)]
Out[50]: 
[PosixPath('.'),
 PosixPath('.pypirc'),
 PosixPath('.python_history'),
 PosixPath('lshw'),
 PosixPath('.gstreamer-0.10'),
 PosixPath('.gstreamer-0.10/registry.x86_64.bin'),
 PosixPath('.gconf'),
 PosixPath('.gconf/apps'),
 PosixPath('.gconf/apps/gnome-terminal'),
 PosixPath('.gconf/apps/gnome-terminal/%gconf.xml')]

这是sjthebats answer的面向对象版本必不可少的。注意Path.glob **模式只返回目录!

于 2014-04-08T21:09:37.500 回答
2

os.scandir()是一个“函数返回目录条目以及文件属性信息,os.listdir()为许多常见用例提供更好的性能[比]。” 它是一个不内部使用的迭代器os.listdir()

于 2020-11-03T19:04:57.610 回答
0

您可以使用path.py。不幸的是,作者的网站不再存在,但您仍然可以从 PyPI 下载代码。该库是os模块中路径函数的包装器。

path.py提供了一种walkfiles()方法,该方法返回一个生成器,该生成器对目录中的所有文件进行递归迭代:

>>> from path import path
>>> print path.walkfiles.__doc__
 D.walkfiles() -> iterator over files in D, recursively.

        The optional argument, pattern, limits the results to files
        with names that match the pattern.  For example,
        mydir.walkfiles('*.tmp') yields only files with the .tmp
        extension.

>>> p = path('/tmp')
>>> p.walkfiles()
<generator object walkfiles at 0x8ca75a4>
>>> 
于 2009-11-09T01:10:51.237 回答
0

gerrit答案的附录。我想让一些东西更灵活。

列出pth匹配给定的所有文件,如果是pattern,也可以列出目录only_fileFalse

from pathlib import Path

def walk(pth=Path('.'), pattern='*', only_file=True) :
    """ list all files in pth matching a given pattern, can also list dirs if only_file is False """
    if pth.match(pattern) and not (only_file and pth.is_dir()) :
        yield pth
    for sub in pth.iterdir():
        if sub.is_dir():
            yield from walk(sub, pattern, only_file)
        else:
            if sub.match(pattern) :
                yield sub
于 2016-05-09T13:33:28.787 回答