Python递归遍历目录树,并记录异常

比较os.listdir()与os.walk()

用os.listdir(path)可查询path目录下的所有文件,用os.walk(path)可查询path目录及其子目录下的所有文件。
但是os.walk()不能控制遍历文件树的深度,而且默认会忽略发生的异常,把没有访问权限的目录直接判定为空目录。如下:

>>> import os
>>> os.listdir("/root")     # 使用os.listdir()查询,遇到异常会直接抛出
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
PermissionError: [Errno 13] Permission denied: '/root'
>>> list(os.walk("/root"))          # os.walk()默认会忽略发生的异常
[]
>>> list(os.walk("/root", onerror=print))   # 可传入onerror参数,记录发生的异常
[Errno 13] Permission denied: '/root'
[]

查找所有文件

基于os.walk()自定义一个函数:每次迭代时遍历一个子目录。
采用生成器模式,可以让程序一边遍历文件,一边进行处理。

def find_all_files(path: str = '.', onerror=print):
    """
    查找`path`目录及其子目录下的所有文件,返回一个生成器。
      - `path`: 一个已存在的目录。
      - `onerror`: 记录异常的函数名。
    """
    for basepath, dirnames, filenames in os.walk(path, onerror=onerror):
        paths = []
        for i in dirnames + filenames:
            paths.append(os.path.join(basepath, i))
        yield paths


if __name__ == "__main__":
    for paths in find_all_files("."):
        print(paths)

查找并筛选文件

基于os.listdir()自定义一个函数,查找文件,控制查找文件树的深度,并根据shell通配符、正则表达式筛选文件。

import os
import fnmatch
import re

def find_file(directory='.', depth=-1, pattern=None, re_pattern=None, onerror=print) -> list:
    """
    查找文件,并进行筛选。
    - `directory`: 一个已存在的目录。
    - `depth`: 查找文件树的最大深度。如果值为负数,则无限深度。
    - `pattern`: 根据shell通配符筛选文件名。
    - `re_pattern`: 根据正则表达式筛选文件名。
    - `onerror`: 一个可调用的参数,用于记录报错。
    
    工作在递归模式。如果处理上千个文件,可能要花费好几秒。

    示例:
    >>> find_file('.', pattern='*.py')
    >>> find_file('.', re_pattern='.*.py')
    """
    if not os.path.isdir(directory):
        raise ValueError("{} is not an existing directory.".format(directory))

    try:
        file_list = os.listdir(directory)
    except PermissionError as e:    # Sometimes it does not have access to the directory
        onerror("PermissionError: {}".format(e))
        return -1

    path_list = []
    for filename in file_list:
        path = os.path.join(directory, filename)
        if depth != 0 and os.path.isdir(path):
            sub_list = find_file(path, depth-1, pattern, re_pattern, onerror)
            if sub_list != -1:
                path_list.extend(sub_list)
            continue
        if pattern and not fnmatch.fnmatch(filename, pattern):
            continue
        if re_pattern and not re.findall(re_pattern, filename):
            continue
        path_list.append(path)

    return path_list

关于路径分隔符 / 和 \

  • 类Unix平台、Web使用正斜杠 / 作为路径分隔符,而Windows使用反斜杠 \ 作为路径分隔符,所以在字符串出现中时要转义或者加上前缀r。
  • Python访问某个路径时可以用正斜杠也可以用反斜杠,比如 “C:/Users”、“C:\Users”、r"C:\Users",因为Python内置的函数会自动识别并转换这几种路径分隔符。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值