os.walk() 比 pathlib.rglob() 更可控:可提前剪枝dirs、逐行读取防内存溢出、细化异常处理、用生成器yield避免大列表,且需注意混合编码与硬链接问题。

用 os.walk() 遍历目录比 pathlib.rglob() 更可控
递归查找文件时,os.walk() 能明确分离目录遍历、子目录列表和当前层文件列表,便于在进入某目录前就判断是否跳过(比如排除 __pycache__ 或 .git),而 pathlib.Path.rglob("*") 会无差别展开所有层级,遇到符号链接循环或超深嵌套时容易失控。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 优先用
os.walk(top, topdown=True),设topdown=True(默认)才能在处理子目录前修改dirs列表实现剪枝 - 对每个
root, dirs, files元组,先就地过滤dirs:例如dirs[:] = [d for d in dirs if d not in {".git", "__pycache__"}] - 避免直接对
files做全文扫描——先用后缀快速筛出目标文档类型,比如只检查.txt、.py、.md
匹配文件内容时别用 read() 一次性加载大文件
遇到几百 MB 的日志或数据文件,file.read().find(keyword) 会把整个文件拖进内存,可能触发 MemoryError 或显著拖慢搜索。更稳妥的方式是逐行读取,用 in 判断每行是否含关键字。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 打开文件时加
errors="ignore",避免二进制内容或编码异常中断流程,例如open(filepath, encoding="utf-8", errors="ignore") - 对文本文件,用
for line in f:迭代,而非f.readlines()—— 后者仍会预加载全部行 - 若需支持大小写不敏感匹配,统一转小写比用
re.IGNORECASE开销小:if keyword.lower() in line.lower():
遇到 UnicodeDecodeError 不要静默跳过所有异常
直接捕获 Exception 并 continue 会导致无法区分是权限不足、路径不存在,还是真实编码问题,后续排查困难。错误类型必须细化处理。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 明确捕获三类异常:
PermissionError(跳过)、FileNotFoundError(通常不会出现,但 walk 中偶有竞态)、UnicodeDecodeError(换编码重试或记录) - 对
UnicodeDecodeError,可降级尝试gbk或latin-1(后者永不失败,但可能乱码):open(..., encoding="latin-1") - 打印警告时带上文件路径和错误原因,例如:
print(f"[WARN] {filepath}: {e}"),方便定位顽固文件
用生成器函数返回结果,别拼大列表
如果目标目录含上万文件,把所有匹配路径塞进一个 list 再返回,既占内存又延迟首次输出。用户往往只想“看到第一个结果”或“取前 10 个”,没必要等全量扫描完。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 定义函数时用
yield逐个产出匹配的filepath,调用方可用next()、itertools.islice()或简单for控制消费节奏 - 避免在生成器内做耗时操作(如重复编译正则),把
re.compile(keyword_re)提到函数外 - 若需统计总数,不要用
len(list(generator)),改用计数器变量或事后调用sum(1 for _ in generator)
真正难处理的是混合编码的遗留项目和硬链接导致的重复计数,这两个点容易被当成“搜得慢”忽略掉。


















