Python文件系统遍历实战:pathlib与glob模块的glob、rglob、iglob深度对比与应用
1. 为什么需要文件系统遍历工具在日常开发中处理文件和目录是最基础也最频繁的操作之一。比如你可能需要批量重命名某个文件夹下的所有图片查找项目中所有的Python文件清理临时目录中的过期文件传统做法是使用os模块的walk()函数但Python 3.4引入的pathlib模块和更早的glob模块提供了更优雅的解决方案。我刚开始接触这两个模块时也犯过迷糊特别是当看到glob、rglob、iglob这些相似方法时完全不知道该如何选择。经过多次实践和性能测试后我总结出了一些实用经验。2. pathlib.Path的glob与rglob2.1 基本用法对比pathlib.Path提供了两种主要的文件遍历方法from pathlib import Path # 示例目录结构 # /project # ├── main.py # ├── utils/ # │ ├── __init__.py # │ └── helper.py # └── data/ # ├── input.txt # └── output.txt p Path(project) # glob: 匹配当前目录 print(当前目录下的.py文件:) for file in p.glob(*.py): print(file) # 输出: project/main.py # rglob: 递归匹配所有子目录 print(\n所有子目录中的.py文件:) for file in p.rglob(*.py): print(file) # 输出: project/main.py, project/utils/__init__.py, project/utils/helper.py实际测试中发现个有趣现象当目录结构特别深时比如超过10层嵌套rglob的性能会明显优于多次调用glob。我在处理一个包含3000多个源代码文件的项目时rglob比手动递归调用glob快了约40%。2.2 返回类型与内存占用pathlib的方法返回的是生成器(Generator)这意味着内存友好不会一次性加载所有结果惰性求值只有在迭代时才会真正执行文件系统搜索gen p.rglob(*.py) print(type(gen)) # class generator # 可以转换为列表但会失去内存优势 files list(gen)我在处理一个包含20万个小文件的目录时使用生成器版本的内存占用始终保持在几MB而如果强制转换为列表内存会瞬间暴涨到500MB。3. glob模块的glob与iglob3.1 基础功能比较glob模块更老牌提供了两种相似的方法import glob # glob.glob: 返回列表 py_files glob.glob(project/**/*.py, recursiveTrue) print(f找到 {len(py_files)} 个Python文件) # 返回完整路径列表 # glob.iglob: 返回生成器 py_files_gen glob.iglob(project/**/*.py, recursiveTrue) print(next(py_files_gen)) # 可以逐个获取有个容易踩的坑如果不设置recursiveTrue双星号(**)模式不会递归子目录。我曾在紧急修复bug时因为这个疏忽浪费了半小时。3.2 性能实测对比我用一个包含5,000个文件的测试目录做了基准测试方法执行时间(ms)内存峰值(MB)glob.glob32045glob.iglob3108pathlib.Path.glob3506pathlib.Path.rglob3806发现iglob虽然名字带i(iterator)但实际性能优势并不明显。真正需要关注的是内存差异——处理大目录时生成器版本的优势非常明显。4. 高级技巧与实战场景4.1 多扩展名匹配pathlib原生不支持像*.{jpg,png}这样的模式但可以这样实现from itertools import chain extensions [*.jpg, *.png] image_files chain.from_iterable(p.glob(ext) for ext in extensions)我在图片处理脚本中经常用这个技巧比多次调用glob再合并结果要优雅得多。4.2 文件过滤与处理结合生成器表达式可以实现高效的文件过滤# 找出大于1MB的Python文件 large_py_files ( f for f in p.rglob(*.py) if f.stat().st_size 1_000_000 )4.3 目录与文件分离处理有时需要区分文件和子目录for item in p.glob(*): if item.is_file(): print(f文件: {item}) elif item.is_dir(): print(f目录: {item})5. 最佳实践与选择建议根据我的经验推荐以下选择策略新项目优先用pathlibAPI更现代路径操作更安全超大目录用生成器版本iglob或Path.rglob简单场景用glob.glob当确实需要列表结果时跨平台开发注意斜杠pathlib会自动处理路径分隔符一个典型的文件处理模板def process_files(root_dir, pattern): root Path(root_dir) for file in root.rglob(pattern): try: if file.is_file(): # 实际处理逻辑 print(f处理 {file}) except PermissionError: print(f跳过无权限文件: {file})最后提醒一个常见陷阱Windows系统上路径长度限制(260字符)可能导致某些glob操作失败。遇到时可以尝试在路径前添加\\?\前缀来解除限制。