os.walk 比 glob("*/") 更稳,因其原生支持目录遍历、可捕获错误、自动跳过不可读目录,而 glob 递归需显式 recursive=true,且遇权限拒绝或路径过长会直接抛异常中断。

os.walk 为什么比 glob("**/*") 更稳?
Python 3.12 中 glob.glob 默认不支持递归通配符 **,除非显式传入 recursive=True;而即使开了,它在遇到权限拒绝、符号链接循环或路径过长时容易直接抛 FileNotFoundError 或 OSError,中断整个遍历。相比之下,os.walk 是原生设计用于目录遍历的,错误可捕获、路径可控、无需额外参数就能自然跳过不可读目录。
实操建议:
- 用
os.walk时加topdown=True(默认),便于在进入子目录前过滤掉不想进的路径(比如跳过.git) - 若需只遍历文件(不含目录),对每层返回的
files列表做处理,别误用dirs列表 - 遇到
PermissionError,用try/except包住os.walk的调用,或改用os.walk(..., onerror=handler)
glob("**/*", recursive=True) 的三个关键限制
glob.glob 在 Python 3.12 下启用递归必须带 recursive=True,否则 ** 被当字面量处理——这是最常被忽略的配置项。它还有两个隐性约束:
- 路径必须是字符串,不能是
pathlib.Path对象(否则报TypeError: expected str, bytes or os.PathLike object) - 不区分“文件”和“目录”,
**/*会同时匹配两者;若只想文件,得额外用os.path.isfile()或pathlib.Path.is_file()过滤 - 底层依赖
os.listdir,但不会像os.walk那样自动跳过无法访问的子目录;一旦某个子目录打不开,整个glob调用就失败
示例:正确写法是 glob.glob("src/**/*", recursive=True);错误写法是 glob.glob("src/**/*")(无 recursive=True)或 glob.glob(Path("src") / "**" / "*")(类型错)。
怎么安全地拿到所有文件路径(含绝对路径、相对路径、大小)?
多数实际需求不只是“列出路径”,还要快速获取元信息。用 os.walk + os.path.join + os.stat 组合最轻量:
import os
for root, dirs, files in os.walk("project"):
for f in files:
path = os.path.join(root, f)
try:
st = os.stat(path)
print(f"{path} {st.st_size}")
except (OSError, FileNotFoundError):
continue # 跳过无法 stat 的文件(如被删除、权限不足)
注意:os.stat 比 pathlib.Path(path).stat() 略快,且不触发任何隐式路径解析;如果已用 pathlib,记得用 p.resolve() 前先判断是否存在,否则 resolve() 可能抛异常。
Windows 下路径分隔符和编码问题怎么避坑?
Python 3.12 在 Windows 上仍默认用 \ 分隔路径,但 glob 和 os.walk 都接受正斜杠 / 输入(内部自动转换)。真正容易出问题的是:
- 用
glob匹配含中文或特殊符号的路径时,确保源字符串是 UTF-8 编码(脚本开头加# -*- coding: utf-8 -*-),否则 Windows 控制台可能解码失败 -
os.walk返回的root、dirs、files都是str,不是bytes;但如果路径本身含非法字节(罕见),os.walk会跳过该层级且不报错——这点很难调试,建议优先用pathlib.Path替代原始字符串操作 - 避免拼接路径时混用
\和/,统一用os.path.join()或pathlib.Path / "sub"
深层嵌套目录本身没上限,但 Windows 对单路径长度限制为 260 字符(除非启用长路径支持),这时 os.walk 会跳过超长路径,而 glob 直接报错——这个差异在自动化批量处理时特别关键。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











