代码之家  ›  专栏  ›  技术社区  ›  Byte Commander

递归深度有限的旅行目录树

  •  9
  • Byte Commander  · 技术社区  · 8 年前

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

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

    我如何在Python 3中做到最好?

    当前我使用 os.walk 要在循环中处理无限深度的所有文件,请执行以下操作:

    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 如果该水平超过期望的最大值,则循环。

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

    2 回复  |  直到 5 年前
        1
  •  18
  •   Kevin    7 年前

    我认为最简单、最稳定的方法是复制 os.walk straight out of the source 并插入您自己的深度控制参数。

    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):
        #...
    

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

    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)
    
        2
  •  12
  •   Arty    3 年前

    从python 3.5操作系统开始。scandir用于操作系统。步行而不是os.listdir。它的工作速度快很多倍。我纠正了一点@kevin样本。

    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 walk(path, maxdepth-1):
                    yield x
    
    for x in walk(".", 2):
        print(x)