使用Python自下而上遍历目录树

1 投票
1 回答
4993 浏览
提问于 2025-04-18 14:30

我想找个方法,用Python从底部向上遍历一个文件夹树。我的目标是找到一个文件夹,它的位置可能在当前文件夹的上面或下面,具体距离不确定。

我画了个图,希望能让我的问题更清楚: 目录树

红色框是起点,绿色框是可能的目标文件夹位置,实际上只需要找到其中一个就可以了,不用两个都找。

如果目标文件夹是 /One/_One/_One,我希望脚本先往上走到 /One,然后再一路往下找到 /One/_One/_One。

如果目标文件夹是 /Three,我希望脚本也先做同样的事情,接着去 /Two 和 /Two/_Two,没找到后,最后到达 /Three。或者说,先检查完 /One 后,它会去根目录 /,然后找到 /Three,这样就跳过了 /Two 的遍历。

任何帮助都非常感谢。我一直在看 os.path 和 os.walk 的方法,但还没找到解决方案。

1 个回答

7

这个问题的关键在于关于 os.walk 的文档说明:

当设置为 True 时,调用者可以直接修改 dirnames 列表(比如用 del 或切片赋值),walk() 只会进入那些名字仍在 dirnames 中的子目录。

有了这个信息,你可以把这个问题想象成在树上搜索。你从树的根节点开始,每次没有找到解决方案时,就退回上一层,再次进行树的搜索,并在到达那里时移除上一次搜索的根节点

假设我有以下内容:

start_path    = 'ABC0123/Comp/Scripts'
searching_for ='Some_File'

我可以这样做:

last_root    = start_path
current_root = start_path
found_path   = None
while found_path is None and current_root:
    pruned = False
    for root, dirs, files in os.walk(current_root):
        if not pruned:
           try:
              # Remove the part of the tree we already searched
              del dirs[dirs.index(os.path.basename(last_root))]
              pruned = True
           except ValueError:
              pass
        if searching_for in files:
           # found the file, stop
           found_path = os.path.join(root, searching_for)
           break
     # Otherwise, pop up a level, search again
     last_root    = current_root
     current_root = os.path.dirname(last_root)

在第一次迭代中,它会搜索 'ABC0123/Comp/Scripts' 这个目录。如果没有找到 'Some_File',它就会搜索 'ABC0123/Comp' 目录,跳过 'Scripts' 目录。然后,它会搜索 'ABC0123' 目录,跳过 'Comp' 以及它下面的所有内容。

下面是遍历过程的一些示例输出。CRcurrent_rootLRlast_rootExploring 是当前 walk 步骤中的 root。在这个例子中,文件位于 ABC0123/Paint/Output

CR: 'ABC0123/Comp/Scripts/', LR: 'ABC0123/Comp/Scripts/'
Exploring: 'ABC0123/Comp/Scripts/'
CR: 'ABC0123/Comp/Scripts', LR: 'ABC0123/Comp/Scripts/'
Exploring: 'ABC0123/Comp/Scripts'
CR: 'ABC0123/Comp', LR: 'ABC0123/Comp/Scripts'
Exploring: 'ABC0123/Comp'
Exploring: 'ABC0123/Comp/Output'
CR: 'ABC0123', LR: 'ABC0123/Comp'
Exploring: 'ABC0123'
Exploring: 'ABC0123/Lighting'
Exploring: 'ABC0123/Lighting/Output'
Exploring: 'ABC0123/Paint'
Exploring: 'ABC0123/Paint/Output'

>>> found_path
'ABC0123/Paint/Output/Some_File'

另外要注意的是,实际上并不清楚你是在搜索目录还是文件。我的代码假设你是在找文件,但如果你是在找目录,只需将:

if searching_for in files:

改为

if searching_for in dirs:

但要注意,在这两种情况下,它都假设你要搜索的是一个唯一的文件或目录(在最大树深度内),或者你遇到的第一个实例就是你要找的。例如,按照现在的写法,你不能专门搜索 'Paint/Output'。不过,你应该能很容易地找到修改搜索条件的方法来实现这一点。

撰写回答