用 os.scandir() 替代 os.walk() 可显著提升超大文件夹磁盘占用统计性能,因其返回带 stat 缓存的 DirEntry 对象,避免重复系统调用与路径拼接,并配合栈式遍历、平台化路径处理(如 Windows 长路径前缀)及异常容错,能稳定高效应对百万级文件场景。

用 os.scandir() 替代 os.walk() 能显著提速
对超大文件夹(比如含数万子目录、百万级文件)求磁盘占用,os.walk() 是常见选择,但它会为每个目录反复调用 stat() 且构建大量路径字符串,内存和 CPU 开销都大。os.scandir() 返回 DirEntry 对象,自带 stat() 缓存,且支持 is_file()/is_dir() 快速判断,避免额外系统调用。
实操建议:
- 递归遍历时,对每个
DirEntry先用entry.is_file(follow_symlinks=False)判断是否为真实文件(跳过符号链接) - 仅对文件调用
entry.stat().st_size,不要用os.path.getsize()—— 后者会再次触发stat() - 遇到权限错误(如
PermissionError)直接跳过,不中断整个遍历 - 避免拼接完整路径:用
entry.path或os.path.join(parent_path, entry.name)仅在必要时生成
注意 st_size 和实际磁盘占用的区别
st_size 是文件逻辑大小(字节数),但磁盘实际占用取决于文件系统块大小(如 4KB)。一个 1B 的文件通常也占 4KB 磁盘空间。若需真实磁盘用量,得用 st_blocks * st_blksize(POSIX 系统),但 Windows 不支持该字段。
实操建议:
- Linux/macOS 下可用
entry.stat().st_blocks * entry.stat().st_blksize获取近似磁盘块占用(注意st_blocks单位是 512 字节,需换算) - 跨平台脚本中,优先用
st_size—— 它语义明确、稳定、可比性强;若真需物理块占用,应单独封装平台检测逻辑 - 稀疏文件、硬链接、压缩卷等场景下,
st_size和磁盘用量偏差更大,此时无通用解法,只能注明“仅供参考”
避免递归爆栈和内存泄漏的实用技巧
超深嵌套目录(如 >1000 层)可能让纯递归版本触发 RecursionError;而一次性收集所有路径再统计,又容易因路径字符串过多耗尽内存。
实操建议:
- 用栈模拟递归:维护一个
list存待处理目录路径,pop()一个,scandir()扫一遍,把子目录append()进去 —— 控制深度无压力 - 每处理完一个目录就清空局部变量(如临时
list),尤其避免在闭包或生成器里累积引用 - 对超大结果,考虑用
yield分批返回子目录统计,而非全量累加到一个数字再返回 - 用
try/except包裹scandir()调用,捕获FileNotFoundError(路径被删)、NotADirectoryError(被替换成文件)等瞬态错误
Windows 上 \? 前缀解决长路径限制
Windows 默认路径长度上限 260 字符,超长路径会抛 FileNotFoundError 或静默失败。即使 Python 3.6+ 支持长路径,仍需显式启用。
实操建议:
- 传入路径前,先用
os.path.abspath(path)转绝对路径,再加r"\?"前缀(仅 Windows) - 注意:
\?路径不支持相对路径、./..、通配符,且必须是本地路径(不能是 UNC 路径,除非用\?UNC) - 检查
sys.platform == "win32"再做前缀处理,其他系统跳过 - 加前缀后,部分 API(如
os.path.isdir())可能失效,应继续依赖DirEntry的方法
用 os.scandir() + 栈式遍历 + 平台适配路径处理,基本覆盖绝大多数超大文件夹场景。真正棘手的是挂载的网络文件系统(NFS/SMB)或加密容器——它们的延迟和权限模型会让统计变慢甚至卡死,这种情况下,别硬扛,加超时和进度提示更实际。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











