Python递归遍历文件夹,如何使用生成器返回每个文件名?

贴一段自己写的代码,主要实现以下功能:

  1. 递归遍历源目录( src_path )下的文件,可以用于检测文件
  2. 可以将源目录下的所有文件处理后传到目标目录(det_path)中,即可以对源文件批量处理,将 print 替换成对应方法即可
import os
def dir_walk(src_path,det_path=None):
    if os.path.isdir(src_path):
        if det_path and not os.path.isdir(det_path):
            os.makedirs(det_path)
        for name in os.listdir(src_path):
            _src_path = os.path.join(src_path,name)
            _det_path = det_path and os.path.join(det_path,name)
            yield from dir_walk(_src_path,_det_path)
    if os.path.isfile(src_path):
        yield src_path,det_path
for i,_ in dir_walk('/home'):
    print(i)

主要有几个疑问,大家帮忙试着解答下哈:

  1. 代码的执行效率如何,递归时使用 yield 会不会没有发挥 yield 的作用
  2. yield from 和递归一起使用感觉怪怪的,这是我试出来的,这样写竟然可以用,谁帮忙解释下怎么的语法啊
  3. 为了让方法可以同时满足我上面说的两种功能,所以加的第二个参数默认为 None,然后方法里一些判断,当然这样就降低了代码的效率,有更好的解决办法吗?

Python递归遍历文件夹,如何使用生成器返回每个文件名?

15 回复

这个帖子上去啊


import os

def walk_files_generator(start_path):
    """
    使用生成器递归遍历文件夹并返回每个文件的完整路径
    
    Args:
        start_path: 起始目录路径
    
    Yields:
        每个文件的完整路径
    """
    # 遍历当前目录下的所有条目
    for entry in os.listdir(start_path):
        full_path = os.path.join(start_path, entry)
        
        # 如果是文件,直接yield
        if os.path.isfile(full_path):
            yield full_path
        # 如果是目录,递归遍历
        elif os.path.isdir(full_path):
            # 使用yield from将子生成器的结果传递出去
            yield from walk_files_generator(full_path)

# 使用示例
if __name__ == "__main__":
    # 指定要遍历的目录
    target_dir = "/path/to/your/directory"  # 替换为实际路径
    
    # 使用生成器遍历文件
    for file_path in walk_files_generator(target_dir):
        print(file_path)
    
    # 或者转换为列表
    # all_files = list(walk_files_generator(target_dir))

这个实现的核心是yieldyield from

  1. yield在遇到文件时直接返回文件路径
  2. yield from用于处理递归调用,将子目录的生成器结果直接传递到当前生成器

相比一次性返回所有文件的列表,生成器版本的优势是:

  • 内存效率高:一次只处理一个文件
  • 可以提前中断遍历
  • 支持惰性求值

如果你只需要文件名而不是完整路径,可以在yield时处理:

yield os.path.basename(full_path)  # 只返回文件名

或者使用os.walk的生成器版本:

def walk_files_os_walk(start_path):
    """使用os.walk的实现"""
    for root, dirs, files in os.walk(start_path):
        for file in files:
            yield os.path.join(root, file)

用生成器处理文件遍历更高效。

os.walk 有什么满足不了吗?

过早优化是万恶之源。能用就行

递归就是坑坑坑坑

不能复制到新的文件夹下,它只能遍历

知道 dir 命令嚒

python3.5 及以上用 os.scandir 会更快一点

不光是遍历,主要是第二个参数,可以用于复制文件等

什么啊?

是指替换 os.listdir 吧

没看懂其中有什么是 os.walk 不能做,而这段代码能做的

和 os.walk()差不多, 具体可以看官方文档

如果不用 yield,递归是很容易实现的,因为最近学到了,所以就想把它包装成一个方法; os.walk 也可以勉强完成处理后复制文件的功能,但用起来会很别扭


不好意看错了 os.walk 文档下面解释 Changed in version 3.5: This function now calls os.scandir() instead of os.listdir(), making it faster by reducing the number of calls to os.stat().

scandir 和 walk 一般都直接用来迭代目录,还以为这俩是一样的

回到顶部