Python 中 os.scandir() 在目录树中的条目(文件和文件夹)列表

list of entries (files and folders) in a directory tree by os.scandir() in Python

提问人:Leo Sam 提问时间:7/11/2022 更新时间:11/21/2022 访问量:1844

问:

我使用“os.walk()”列出目录树中的所有子文件夹和文件,但听说“os.scandir()”的工作速度提高了 2 倍 - 20 倍。所以我尝试了这段代码:

def tree2list (directory:str) -> list:
    import os
    tree = []
    counter = 0
    for i in os.scandir(directory):
        if i.is_dir():
            counter+=1
            tree.append ([counter,'Folder', i.name, i.path])  ## doesn't list the whole tree
            tree2list(i.path)
            #print(i.path)  ## this line prints all subfolders in the tree
        else:
            counter+=1
            tree.append([counter,'File', i.name, i.path])
            #print(i.path)  ## this line prints all files in the tree
    return tree

测试时:

    ## tester
folder = 'E:/Test'
print(tree2list(folder))

我只得到了根目录的内容,而没有从树层次结构下的子目录中得到任何内容,而上面代码中的所有 print 语句都可以正常工作。

[[1, 'Folder', 'Archive', 'E:/Test\\Archive'], [2, 'Folder', 'Source', 'E:/Test\\Source']]

我做错了什么?,我该如何解决?!

蟒蛇 python-3.x 扫描目录

评论

0赞 Finomnis 7/11/2022
这回答了你的问题吗?如何使用os.scandir()在目录树上递归返回DirEntry对象?
0赞 Finomnis 7/11/2022
您永远不会从递归函数调用中传播找到的路径。 是当前调用的本地调用,它不会在递归调用之间共享。而且你永远不会把下一次递归的路径写进去,你只把最上面的路径写进去。treetree2list
0赞 Leo Sam 7/11/2022
我在 peps.python.org/pep-0471/#examples 中使用了相同的“get_tree_size”函数。它使用的方式与我使用递归的方式相同!@Finomnis
0赞 Finomnis 7/11/2022
不,它没有。 - 这是将树的下半部分的结果添加到总数中的地方。这正是你所缺少的。total += get_tree_size(entry.path)
1赞 Mark Tolonen 7/11/2022
os.walk:“在 3.5 版更改:此函数现在调用 os.scandir() 而不是 os.listdir(),通过减少对 os.stat() 的调用次数使其更快。所以只需使用 os.walk。

答:

3赞 Gelineau 7/11/2022 #1

使用生成器 (, ) 允许使用简洁的代码管理递归:yieldyield from

from pprint import pprint
from typing import Iterator, Tuple


def tree2list(directory: str) -> Iterator[Tuple[str, str, str]]:
    import os

    for i in os.scandir(directory):
        if i.is_dir():
            yield ["Folder", i.name, i.path]
            yield from tree2list(i.path)
        else:
            yield ["File", i.name, i.path]


folder = "/home/yfgy6415/dev/tmp"
pprint(list(tree2list(folder)))

或者:如果你想要计数器。pprint(list(enumerate(tree2list(folder), start=1)))

3赞 Finomnis 7/11/2022 #2

您的代码几乎可以工作,只需要稍作修改:

def tree2list(directory: str) -> list:
    import os
    tree = []
    counter = 0
    for i in os.scandir(directory):
        if i.is_dir():
            counter += 1
            tree.append([counter, 'Folder', i.name, i.path])
            tree.extend(tree2list(i.path))
            # print(i.path)  ## this line prints all subfolders in the tree
        else:
            counter += 1
            tree.append([counter, 'File', i.name, i.path])
            # print(i.path)  ## this line prints all files in the tree
    return tree

虽然我不明白变量的目的是什么,所以我可能会删除它。counter

此外,我必须同意@Gelineau您的方法非常大量地使用阵列拷贝,因此很可能非常慢。在他的响应中,基于迭代器的方法更适合大量文件。

评论

0赞 Leo Sam 7/11/2022
很好的答案!我删除了“计数器”,因为它没有达到计数器的目的。我打算在传输到 csv 文件时将其用作项目计数器。
0赞 ans2human 11/21/2022 #3

添加到接受的答案中。倘。。。获取目录和子目录中与某些模式匹配的所有文件(例如 *.py):

import os
from fnmatch import fnmatch


def file_tree_fn(root):
    file_list = []
    for python_file in os.scandir(str(root)):
        if python_file.is_dir():
            file_list.extend(file_tree_fn(python_file.path))
        else:
            file_list.append(python_file.path) if fnmatch(python_file.path, "*.py") & python_file.is_file() else None
    return file_list

print(file_tree_fn(root))