Python 如何遍历目录?os.walk、pathlib、glob 有什么区别?
简化版
遍历目录常用 os.walk()、pathlib.Path.rglob() 和 glob.glob()。os.walk() 返回目录、子目录和文件名,适合精细控制;pathlib 面向对象、可读性好;glob 用通配模式匹配路径,适合按模式找文件。
详细版
如果要递归遍历所有文件:
from pathlib import Path
for path in Path("logs").rglob("*.log"):
print(path)
如果要控制是否进入某些目录:
for root, dirs, files in os.walk("logs"):
dirs[:] = [d for d in dirs if d != ".git"]
glob 更像按模式搜索,pathlib 更适合现代代码组织,os.walk 在需要原地修改 dirs、处理大量文件、兼容旧代码时仍常用。
完整版教学
一、目录遍历为什么容易踩坑
目录遍历看起来只是列文件,但真实场景会遇到递归、隐藏目录、符号链接、权限错误、路径分隔符、文件数量巨大等问题。写得粗糙会漏文件、重复遍历或性能很差。
project/
logs/
.git/
data/
link -> ../project
如果跟随符号链接,甚至可能形成循环。面试回答要体现这些边界。
二、os.walk 怎么用
os.walk(top) 每次返回 (root, dirs, files)。root 是当前目录,dirs 是子目录名列表,files 是文件名列表。
import os
for root, dirs, files in os.walk("src"):
for name in files:
print(os.path.join(root, name))
默认自顶向下遍历。自顶向下时,可以原地修改 dirs[:] 来跳过某些目录。
dirs[:] = [d for d in dirs if d not in {".git", "__pycache__"}]
三、pathlib 为什么更推荐
pathlib.Path 把路径当对象,拼接、判断、读取都更直观,跨平台分隔符也更舒服。现代 Python 项目通常更推荐 pathlib。
from pathlib import Path
root = Path("src")
for file in root.rglob("*.py"):
print(file.name, file.parent)
| 操作 | os.path | pathlib |
|---|---|---|
| 拼路径 | os.path.join(a,b) | Path(a) / b |
| 判断文件 | os.path.isfile(p) | p.is_file() |
| 递归匹配 | os.walk + 判断 | Path.rglob() |
新代码优先考虑 pathlib,读老代码要熟悉 os.walk。
四、glob 适合什么
glob 用 shell 风格通配符匹配路径。比如 *.py 匹配当前目录 Python 文件,**/*.py 配合 recursive 匹配递归文件。
import glob
glob.glob("src/**/*.py", recursive=True)
pathlib 也有 glob 和 rglob,多数新代码可以直接用 Path.rglob("*.py")。
五、性能和内存要注意什么
glob.glob() 返回列表,匹配结果很多时会一次性占内存。glob.iglob() 返回迭代器,更适合大目录。Path.rglob() 也是迭代式产生路径。
for path in glob.iglob("logs/**/*.log", recursive=True):
handle(path)
如果目录里有 100 万文件,一次性列表会占不少内存;迭代处理更稳。
六、权限和符号链接如何处理
遍历系统目录时可能遇到权限错误。os.walk 有 onerror 参数;pathlib 遍历时需要捕获 OSError。符号链接是否跟随也要明确。
def onerror(err):
print("skip", err.filename)
for root, dirs, files in os.walk("/", onerror=onerror):
...
跟随符号链接可能导致循环或重复扫描。备份、清理工具尤其要谨慎。
七、常见误区与追问
- 误区:glob 默认递归。
**需要配合 recursive 或 pathlib 的 rglob。 - 误区:遍历目录不会出错。 权限、删除中的文件、符号链接都会导致异常。
- 误区:一次性拿列表总没问题。 大目录会消耗大量内存,优先迭代处理。
- 追问:如何跳过 .git?
os.walk自顶向下时修改dirs[:]。 - 追问:pathlib 和 os.path 怎么选? 新代码 pathlib 可读性好,老代码 os.path 常见。
- 追问:如何只找某类文件? glob/rglob 模式,或遍历后判断 suffix。
- 追问:符号链接要不要跟随? 看业务,默认谨慎,避免循环。
八、加强记忆
目录遍历记成“三件工具”:os.walk 精细控制,pathlib.rglob 现代好读,glob 模式匹配。大目录用迭代,跳目录改 dirs[:],权限和符号链接要防。会这些,比只写一个递归函数稳得多。