如何使用os.scandir()递归地返回一个目录树上的DirEntry对象?

30

Python 3.5的os.scandir(path)函数返回轻量级的DirEntry对象,非常有助于获得关于文件的信息。但是,它仅适用于直接传递给它的路径。是否有一种方法将其包装在递归函数中,以便访问给定路径下的所有子目录?


1
看看 os.walk()。它可能比您想要的更加严厉,但应该比创建自己的解决方案更简单。 - skrrgwasme
1个回答

57

您可以使用os.walk()递归扫描,或者如果需要DirEntry对象或更多控制,则编写像下面的递归函数scantree()

try:
    from os import scandir
except ImportError:
    from scandir import scandir  # use scandir PyPI module on Python < 3.5

def scantree(path):
    """Recursively yield DirEntry objects for given directory."""
    for entry in scandir(path):
        if entry.is_dir(follow_symlinks=False):
            yield from scantree(entry.path)  # see below for Python 2.x
        else:
            yield entry

if __name__ == '__main__':
    import sys
    for entry in scantree(sys.argv[1] if len(sys.argv) > 1 else '.'):
        print(entry.path)

注意:

  • PEP 471os.scandir()文档中有更多的示例。
  • 您还可以在循环中添加各种逻辑以跳过以'.'开头的目录或文件等。
  • 像这样的递归函数中,通常希望在is_dir()调用上设置follow_symlinks=false,以避免符号链接循环。
  • 在Python 2.x中,请使用以下内容替换yield from行:

    for entry in scantree(entry.path):
        yield entry
    

1
鉴于 os.scandir 仅存在于 Python 3.5 中,Python 2 的回退代码可能不再需要。 :-) 编辑: 啊,你编写了导入 PyPI 模块的代码,如果 os.scandir 不存在,我猜测 PyPI 模块在 2.7 中是可用的? - ShadowRanger
2
@ShadowRanger 说得不错,但这样就可以在使用我的scandir模块时适用于Python < 3.5(包括Python 2.x)。 :-) - Ben Hoyt
@ShadowRanger 我已经添加了一条代码注释来进行澄清。 - Ben Hoyt
4
os.walk与os.scandir -- 我对一个包含400万个目录和文件的目录运行了这两个函数。os.walk用了34分29秒,而os.scandir只用了7分46秒。因此,至少在我的测试中,os.scandir似乎快了4.5倍。 - tzg
3
值得注意的是,作为 PEP 471 的一部分,os.walk 已经更新以在底层使用 os.scandir。 - Slater Victoroff
显示剩余2条评论

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