Python文件系统遍历性能优化核心是减少系统调用:优先用os.scandir()替代os.listdir(),利用DirEntry复用内核缓存信息;Python 3.12+推荐Path.walk();按需调用entry.stat(),避免重复解析路径和无谓stat();善用glob.iglob等惰性接口。
Python中遍历文件系统时,性能瓶颈往往不在代码逻辑本身,而在于I/O调用频次、路径解析开销和不必要的元数据读取。优化核心是减少系统调用次数、避免重复解析、按需获取属性,并合理利用现代API。
os.scandir() 在遍历目录时直接返回 DirEntry 对象,其 stat() 和 is_dir() 等方法可复用内核已读取的目录项信息,避免额外的 stat() 系统调用。而 os.listdir() + 单独 os.path.isdir() 会为每个条目触发两次系统调用(一次读目录,一次查属性)。
for entry in os.scandir(path): if entry.is_dir(): ...
for name in os.listdir(path): if os.path.isdir(os.path.join(path, name)): ...
Python 3.12 引入了 Path.walk(),底层基于 os.scandir(),支持提前终止、跳过子
目录,且接口更简洁。若使用旧版本,可手动封装 os.scandir() 实现类 walk 行为,跳过 os.path.join() 频繁拼接:
DirEntry,用 entry.path(Python 3.12+)或 os.path.join(dir_path, entry.name) 获取完整路径os.path.abspath() 或正则匹配全路径entry.name.endswith(('.py', '.txt')) 比 Path(entry.path).suffix in {'.py', '.txt'} 更快很多场景只需判断是否为目录/文件,或检查修改时间,不必调用 os.stat() 获取全部字段。DirEntry 的 is_file()、is_dir()、stat(follow_symlinks=False) 均可复用缓存信息;若需大小或时间,再显式调用 entry.stat().st_size 或 .st_mtime。
st = os.stat(p); if st.st_size > 0 and stat.S_ISREG(st.st_mode): ...
if entry.is_file() and entry.stat().st_size > 0: —— 只在确认是文件后才读大小当需对大量小文件做轻量操作(如收集路径、检查存在性),可考虑分批处理以缓解GIL影响;对需要内容读取的场景,避免逐个 open().read(),可借助 concurrent.futures.ThreadPoolExecutor 并发读取(注意磁盘随机IO仍是瓶颈)。另外,若目标是统计或搜索,可结合 glob(配合 ** 和 recursive=True)快速定位,它内部也已优化为基于 scandir。
list(Path(".").glob("**/*.py"))(内存友好,惰性生成器可用 glob.iglob)os.listdir() 再手动拼接——这破坏了 scandir 的缓存优势