别再手写递归找文件了!用 Python rglob 一行代码搞定海量搜索
1. 拒绝“面条代码”:你还在用 os.walk 吗?
你是否遇到过这种场景:你需要在一个拥有几十个子文件夹、成百上千个文件的庞大项目中,找出所有的 .log 日志文件进行分析。
作为一个硬核程序员,你的第一反应可能是祭出 os.walk 并在里面嵌套两层 for 循环,或者更惨——自己写一个递归函数(Recursion)去遍历文件夹。
写完之后,代码可能是这样的:
import os
# 传统的痛苦写法
target_files = []
for root, dirs, files in os.walk('my_project'):
for file in files:
if file.endswith('.log'):
target_files.append(os.path.join(root, file))
这段代码能跑,但它并不优雅。它把“遍历逻辑”和“筛选逻辑”混在了一起,不仅难读,而且容易写错。
今天我要介绍的 rglob,就是为了终结这种痛苦而生的。 它是 Python 3.4 引入的 pathlib 模块中的核武器,能让你用一行代码,优雅地完成上述所有工作。
2. 概念拆解:地毯式搜索
生活类比:找遥控器
为了理解 glob 和 rglob 的区别,我们来想象一个生活场景:你在家里找电视遥控器。
-
普通的
glob(Globbing): 这就好比你站在客厅中央,只用眼睛扫视当前房间的桌面和沙发。如果遥控器在卧室或者抽屉里,你是找不到的。glob只匹配当前目录,不进入子目录。 -
rglob(Recursive Glob): 这就是rglob的威力——递归(Recursive)。这就好比你雇佣了一支专业的搜查队。他们不仅看客厅,还会打开每一扇门(进入子目录),拉开每一个抽屉(进入更深层目录),直到把整个家翻个底朝天,找出所有符合特征的目标。
逻辑图解
想象一棵倒立的树(文件系统):
-
起点:你指定的根目录。
-
动作:
rglob会自动沿着树枝向下生长,触达每一个末梢(文件)。 -
筛选:在遍历的同时,它直接过滤出符合你设定模式(Pattern)的文件。
3. 动手实战:三行代码的魔法
让我们抛弃 os 模块,拥抱现代化的 pathlib。
Hello World:找出所有 Python 文件
假设你的项目结构很深,你想列出所有的 .py 文件。
from pathlib import Path
# 1. 定义起点(当前目录)
current_dir = Path('.')
# 2. 发动 rglob 引擎
# 这里的 '*.py' 就是我们要找的特征
python_files = current_dir.rglob('*.py')
# 3. 打印结果
for file_path in python_files:
print(file_path)
代码解析:
-
Path('.'):这是面向对象的文件路径写法,比字符串路径更智能。 -
.rglob('*.py'):核心所在。r代表 Recursive(递归)。它告诉 Python:“去在这个目录及其所有子目录中,找到后缀是.py的家伙。” -
返回值:注意,这里返回的不是一个死列表,而是一个生成器(Generator)。这意味着即使有 100 万个文件,它也不会瞬间撑爆你的内存,而是你通过
for循环要一个,它给一个。
同样的功能,对比一下 os 模块?
-
os模块写法:需要 5-6 行,逻辑嵌套。 -
rglob写法:1 行核心代码,逻辑扁平,语义清晰。
4. 进阶深潜:你必须知道的细节
虽然 rglob 很强,但在生产环境中使用时,有几个关键点需要注意。
A. 通配符的艺术
rglob 支持标准的 Unix shell 风格通配符:
-
rglob('*.jpg'):所有 JPG 图片。 -
rglob('test_*.py'):所有以test_开头的 Python 测试文件。 -
rglob('**/config.yaml'):这也行?是的!其实rglob('*')等同于glob('**/*')。在pathlib中,**本身就代表递归目录。
B. 性能陷阱:不要搜全盘!
千万不要在根目录(如 / 或 C:\)下运行 Path('/').rglob('*')。 因为 rglob 会尝试遍历整个文件系统。如果你的目录包含 node_modules (前端噩梦) 或 .git 文件夹,文件数量可能高达数十万。
最佳实践: 尽量缩小搜索范围,或者在遍历时手动排除特定目录(虽然 rglob 本身不带排除参数,你可能需要在循环中加个 if 判断)。
C. 想要列表怎么办?
前面提到 rglob 返回的是生成器。如果你确定文件数量不多,想直接要一个列表:
# 强制转换为列表
all_images = list(Path('./images').rglob('*.png'))
print(f"一共找到了 {len(all_images)} 张图片")
5. 总结与延伸
核心知识点
-
pathlib是未来:尽量用pathlib.Path替代os.path。 -
rglob是递归神器:它能自动穿透多层文件夹查找文件,无需手写循环。 -
生成器机制:它是惰性求值的,省内存,适合处理大量文件。
浙公网安备 33010602011771号