You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用生成器节省内存:遍历百万文件目录的正确方式?

关于百万文件场景下生成器内存优化的问题解答

这个问题问到点子上了!咱们先拆解你的疑问,再一步步解决:

你的原实现为什么没达到内存优化的目的?

你说得没错,os.walk本身是生成器,但它每个迭代步骤返回的三元组里的第三个元素(也就是文件名列表x[2])是一次性加载到内存的。如果某个目录真的有一百万个文件,这个列表会瞬间占用大量内存——你后面的yield j只是从这个已经占满内存的大列表里逐个输出元素,根本没解决“一次性加载百万文件名”这个源头问题。所以这个实现并不能真正节省内存。

正确的优化方案

核心思路是用懒加载的目录遍历方式,避免一次性把整个目录的文件名都读进内存。Python 3.5+提供的os.scandir()就是干这个的,它是生成器,每次只返回一个目录项对象,内存占用极低。

场景1:仅遍历单个目录(无嵌套子目录)

直接用os.scandir()实现生成器:

import os

def give_object(somepath):
    with os.scandir(somepath) as entries:
        for entry in entries:
            # 只返回文件,跳过目录
            if not entry.is_dir():
                yield entry.name

os.scandir()不会一次性加载所有文件名,每次迭代只生成一个DirEntry对象,哪怕目录里有百万文件,内存占用也会保持在很低的水平。

场景2:递归遍历多层目录(含子目录)

自己基于os.scandir()写递归生成器,替代os.walk:

import os

def give_object(somepath):
    with os.scandir(somepath) as entries:
        for entry in entries:
            if entry.is_dir(follow_symlinks=False):
                # 递归遍历子目录,用yield from简化代码
                yield from give_object(entry.path)
            else:
                yield entry.name

这个实现里,每个目录的遍历都是懒加载的,不管嵌套多少层、单个目录有多少文件,都不会一次性生成大列表,真正做到了内存友好。

补充说明

虽然Python 3.5+的os.walk内部已经改用os.scandir提升效率,但它依然会把每个目录的文件名收集成列表返回,所以还是会出现单个目录百万文件时的内存暴涨问题。因此直接基于os.scandir实现递归才是最优解。

内容的提问来源于stack exchange,提问作者juztcode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:02:40