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

    • 比较os.listdir()与os.walk()
    • 查找所有文件
    • 查找某种后缀名的文件
    • 关于路径分隔符 / 和 \

比较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 "", 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()自定义一个函数:在指定目录下递归遍历某种后缀名的文件,返回这些文件的绝对地址列表。

为了更好的模块化、与外部解耦,加入了多个输入、以及检查输入的语句和日志语句,代码变得臃肿了。

import os


def searchFile(path, suffix=None, depth=-1):
    """
    在目录`path`下检索所有文件,把符合要求的文件名的绝对地址保存成一个list返回。
    如果检索结果为空,则返回值为 [ ] 。
      `path`    : 一个在系统中存在的目录名
      `suffix`  : 文件的后缀名,区分大小写,可以是一个字符串或字符串的元组。默认不区分后缀名
      `depth`   : 最多检索depth层子目录。depth为负数时检索无限层
    """
    if not os.path.isdir(path):
        raise ValueError("'path' must be an existing directory.")

    def __searchFile(path, suffix, depth):
        try:
            dir_list = os.listdir(path)

        # 可能会遇到没有访问权限的文件夹,这里把异常处理掉,以免打断程序运行
        except PermissionError as e:
            print("PermissionError: {}".format(e))
            return -1  # 退出函数,不检索该目录

        file_list = []
        for name in dir_list:
            # 把目录名和文件名合成一个子路径
            sub_path = os.path.join(path, name)

            # 如果子路径是一个文件夹且depth!=0,就递归调用本函数进入该文件夹检索,即深度优先搜索
            if depth != 0 and os.path.isdir(sub_path) == True:
                sub_list = __searchFile(sub_path, suffix, depth-1)
                if sub_list != -1:
                    file_list.extend(sub_list)

            # 如果子路径是一个文件,就判断后缀名是否正确,如果没输入suffix就不考虑后缀名
            elif suffix == None or sub_path.endswith(suffix):
                file_list.append(sub_path)
                print(sub_path)   # 这行只是实时显示,可以注释掉

        return file_list

    return __searchFile(path, suffix, depth)


if __name__ == "__main__":
    searchFile("D:\\", ".txt")

关于路径分隔符 / 和 \

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

你可能感兴趣的:(Python)