关于Python 3:Python 3 – 具有有限递归深度的旅行目录树

Python 3 - travel directory tree with limited recursion depth

我需要递归地处理目录树中的所有文件,但深度有限。

这意味着,例如,要在当前目录和前两个子目录级别中查找文件,但不能再进一步。在这种情况下,我必须处理,如./subdir1/subdir2/file,而不是./subdir1/subdir2/subdir3/file

我如何在Python3中做到最好?

目前,我使用os.walk在这样的循环中处理无限深度的所有文件:

1
2
3
4
for root, dirnames, filenames in os.walk(args.directory):
    for filename in filenames:
        path = os.path.join(root, filename)
        # do something with that file...

我可以考虑一种计算目录分隔符(/root中)的方法,以确定当前文件的层次级别,如果该级别超过了所需的最大值,则确定循环的break

当有大量的子目录需要忽略时,我认为这种方法可能不安全,也可能非常低效。这里的最佳方法是什么?


我认为最简单和最稳定的方法是直接从源代码中复制os.walk的功能,并插入您自己的深度控制参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import os
import os.path as path

def walk(top, topdown=True, onerror=None, followlinks=False, maxdepth=None):
    islink, join, isdir = path.islink, path.join, path.isdir

    try:
        names = os.listdir(top)
    except OSError, err:
        if onerror is not None:
            onerror(err)
        return

    dirs, nondirs = [], []
    for name in names:
        if isdir(join(top, name)):
            dirs.append(name)
        else:
            nondirs.append(name)

    if topdown:
        yield top, dirs, nondirs

    if maxdepth is None or maxdepth > 1:
        for name in dirs:
            new_path = join(top, name)
            if followlinks or not islink(new_path):
                for x in walk(new_path, topdown, onerror, followlinks, None if maxdepth is None else maxdepth-1):
                    yield x
    if not topdown:
        yield top, dirs, nondirs

for root, dirnames, filenames in walk(args.directory, maxdepth=2):
    #...

如果您对所有这些可选参数都不感兴趣,可以大大减少函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os

def walk(top, maxdepth):
    dirs, nondirs = [], []
    for name in os.listdir(top):
        (dirs if os.path.isdir(os.path.join(top, name)) else nondirs).append(name)
    yield top, dirs, nondirs
    if maxdepth > 1:
        for name in dirs:
            for x in walk(os.path.join(top, name), maxdepth-1):
                yield x

for x in walk(".", 2):
    print(x)


从python3.5开始,os.scandir用于os.walk而不是os.listdir。它的工作速度快了很多倍。我更正了@kevin的一些示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os

def walk(top, maxdepth):
    dirs, nondirs = [], []
    for entry in os.scandir(top):
        (dirs if entry.is_dir() else nondirs).append(entry.path)
    yield top, dirs, nondirs
    if maxdepth > 1:
        for path in dirs:
            for x in walkMaxDepth(path, maxdepth-1):
                yield x

for x in walk(".", 2):
    print(x)