os.scandir() 比 os.listdir() 更高效:它返回 direntry 对象,避免一次性加载全部文件名和冗余 stat 调用,速度提升 2–5 倍;推荐配合 with 上下文、is_file()/is_dir() 判断、生成器流式处理及路径前缀优化。

用 os.scandir() 替代 os.listdir()
遍历百万级文件时,os.listdir() 会一次性把所有文件名加载进内存,还额外触发一次 stat() 系统调用(哪怕你只想要名字),性能差、内存涨得快。而 os.scandir() 返回的是 DirEntry 对象,名字、类型、部分属性(如 is_file())可直接获取,无需再 stat,速度通常快 2–5 倍。
实操建议:
- 始终用
with os.scandir(path) as it:上下文管理,避免资源泄漏 - 优先用
entry.is_file()和entry.is_dir()判断类型,别再对每个路径调os.path.isfile() - 如果只需要文件名,直接用
entry.name;需要完整路径再拼os.path.join(path, entry.name)
避免递归时路径拼接和重复 stat
手写递归遍历(比如用 os.walk() 或自己 for + os.listdir())容易在每层都做冗余路径拼接和类型判断,尤其当目录嵌套深、空目录多时,开销明显。
实操建议:
-
os.walk()本身已优化,但默认返回三元组(根、子目录、文件),若只关心文件,跳过空files列表可省点循环 - 改用
pathlib.Path.rglob("*")更简洁,但它会为每个匹配项构造Path对象——百万级下对象创建开销不可忽视,不如os.scandir()手动递归轻量 - 手动递归时,传入当前
DirEntry的path(即entry.path),避免反复os.path.join()
按需处理,别一次性收集所有路径
常见误区:把所有文件路径塞进一个 list 再处理。百万个字符串可能占几百 MB 内存,GC 压力大,还拖慢后续逻辑。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
实操建议:
- 用生成器函数封装遍历逻辑,yield 每个文件路径或
DirEntry,让调用方流式处理 - 例如:匹配特定后缀时,用
if entry.name.endswith((".py", ".js")):在扫描时就过滤,别全读完再filter() - 批量操作(如分批删除/重命名)时,每 1000 个做一次提交,避免单次系统调用过多或阻塞太久
注意 Windows 下的 \? 路径前缀和符号链接
Windows 路径长度超 260 字符会报 WindowsError: [Error 206] The filename or extension is too long,且 os.scandir() 遇到损坏符号链接可能抛 PermissionError 或卡住。
实操建议:
- 路径开头加
r"\?"(如os.scandir(r"\?C:igdir"))绕过 MAX_PATH 限制,但仅限本地路径,不支持 UNC - 捕获
PermissionError和FileNotFoundError,跳过无法访问的条目,别让整个遍历中断 - 用
entry.is_symlink()显式判断,避免误入循环引用的软链目录
真正卡住的往往不是算法,而是没关掉杀毒软件实时扫描,或者用了网络共享路径——本地 SSD 上跑 os.scandir() 递归,百万文件通常在几十秒内完成;挂载的 NAS 或 OneDrive 同步目录,时间可能差一个数量级。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










