os.walk 比 pathlib.rglob 更稳健,支持 onerror 回调跳过权限错误和损坏符号链接;需预编译正则、指定文件编码、逐行读大文件、用 ThreadPoolExecutor 管理线程,并先魔数识别二进制文件。

用 os.walk 遍历目录比 pathlib.rglob 更稳,尤其处理符号链接或权限异常时
默认递归遍历容易在权限不足或损坏的符号链接上直接抛 PermissionError 或 OSError,os.walk 支持 onerror 回调,能跳过并继续——这点 pathlib 没法优雅处理。
- 用
topdown=True(默认)避免进入不想搜的子目录,比如__pycache__或.git - 遇到
PermissionError时,在onerror里pass,别 print,否则大量报错刷屏 - Windows 下注意路径分隔符,
os.path.join(root, file)比拼字符串更安全
正则匹配前必须用 re.compile 预编译,否则多线程下性能暴跌
每次打开文件都用 re.search(pattern, line),等于反复解析正则语法树。多线程里这个开销会被放大,实测 10 线程下慢 3 倍以上。
- 把
re.compile(r"your_pattern", re.IGNORECASE)提到线程外,作为全局变量或传入参数 - 如果 pattern 来自用户输入,记得用
re.escape()包一层,否则foo.bar会误匹配任意字符 - 行内匹配用
pattern.search(line),全文匹配才用findall;前者早停,更快
多线程选 concurrent.futures.ThreadPoolExecutor,别手写 threading
手动管理 threading.Thread 容易漏 join、没异常捕获、线程数失控。而 ThreadPoolExecutor 自带任务队列、结果收集和异常透出机制。
- 线程数别设成
os.cpu_count(),IO 密集型任务设8~16足够,再多反而因 GIL 切换拖慢 - 用
executor.submit(func, *args)提交单个文件处理,别把整个目录列表塞进去 - 每个线程里用
try/except包住文件打开和读取,避免一个坏文件让整个线程崩溃 - 错误信息统一捕获为
Future.exception(),别让异常被吞掉
open() 必须指定 encoding,否则中文匹配全失效
不指定编码时,open() 依赖系统 locale,在 Linux 服务器上常是 ascii 或 ANSI_X3.4-1968,一读中文就抛 UnicodeDecodeError;即使读成功,编码不一致也会导致正则匹配不到。
立即学习“Python免费学习笔记(深入)”;
- 优先试
utf-8,失败再 fallback 到gbk(Windows 文本)或latin-1(二进制混文本) - 别用
errors="ignore"掩盖问题,它会静默丢字,导致关键字漏匹配 - 小文件可全读
f.read(),大文件务必逐行for line in f:,不然内存爆掉
.pyc、.pdf、.zip 这些根本不能当文本读,得先用魔数判断是否跳过。这步漏了,程序要么卡死,要么报一堆解码错误。










