HOWTO · Python

在 Python 中列出目录和子目录中的所有文件

本教程演示如何在 Python 中列出目录和子目录中的所有文件。

本页内容

要收集起始目录下所有文件的路径,可以使用 Python 的 os.walk()。它会遍历目录树,并为每个当前目录提供该目录路径、子目录名称和文件名称。将当前目录路径与每个文件名称拼接起来即可生成文件路径。这里的示例列出的是文件,而不是目录条目。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

from pathlib import Path
import os
import tempfile

with tempfile.TemporaryDirectory() as temporary_directory:
    root = Path(temporary_directory) / "project"
    (root / "reports").mkdir(parents=True)
    for relative_path in ("notes", "data.csv", "reports/summary.txt", "reports/2025.csv"):
        (root / relative_path).write_text("sample", encoding="utf-8")

    for current, directories, filenames in os.walk(root):
        directories.sort()
        for filename in sorted(filenames):
            print(Path(current, filename).relative_to(root))
data.csv
notes
reports/2025.csv
reports/summary.txt

这个临时示例会自行创建目录树,其中包括一个没有扩展名的文件,并输出相对于起始目录的路径。如果要构造完整路径,可以使用 Path(current, filename) 或 os.path.join(current, filename)。相对路径便于保存结果;将文件路径传给其他代码时,绝对路径可能更实用。路径分隔符会根据当前操作系统选择。

使用 os.walk() 递归列出文件

上面的循环使用 os.walk() 作为简单递归列出文件的默认方法。每次迭代时,第一个值是当前目录路径,第二个值是可修改的子目录名称列表,第三个值是当前目录中的文件名称。遍历第三个值即可避免把目录也列入结果。需要稳定的遍历顺序时,可以对子目录名称排序。默认情况下会忽略遍历错误;如果应用程序需要报告错误,可以传入 onerror。

使用 os.listdir() 自定义递归遍历

os.listdir(path) 会返回单个目录中各条目的名称;它不会遍历子目录。要自定义遍历,可以维护一个待检查路径栈。对于每个路径,遍历 os.listdir(path) 的结果,用 os.path.join() 将每个名称与其父路径拼接起来,将文件加入结果,并将目录加入路径栈。使用 os.path.isfile() 和 os.path.isdir() 检查条目类型。这种方式可以控制遍历顺序和筛选规则,但递归逻辑和文件系统错误处理都需要由代码自行实现。

使用 os.scandir() 检查目录条目

os.scandir(path) 会为单个目录生成 DirEntry 对象。通过对象的 is_file() 和 is_dir() 方法,可以方便地判断要收集哪些条目,以及是否要进入子目录。可以采用前面介绍的栈式遍历,并用 with os.scandir(path) as entries: 打开每个目录,以便可靠地关闭迭代器。当条目类型或元数据会影响处理决定时,这种方式很有用。

使用 glob.glob() 按模式匹配文件

需要按模式筛选时,glob.glob(os.path.join(root, "**", "*"), recursive=True) 可以匹配任意层级的名称,包括没有扩展名的名称。启用 recursive=True 后,** 部分会跨越目录。glob 的结果可能包含目录;如果结果必须只包含文件,可以用 os.path.isfile(path) 进行筛选。要选择特定文件类型,可以使用 "**/*.csv" 这类更具体的模式;"*.*" 会排除名称中没有点号的文件。

使用 pathlib.Path 递归列出文件

pathlib.Path(root).rglob("*") 会递归生成根目录下的路径。用 path.is_file() 筛选结果即可排除目录。返回值是 Path 实例,因此无需手动拼接字符串,就能使用 relative_to(root) 和 name 等方法。如果某个 API 要求字符串路径,可以使用 str(path)。

根据任务选择方法

如果需要清晰的默认方案,并希望分别取得文件名称和子目录名称,可以选择 os.walk()。遍历时需要检查条目类型或元数据,可以选择 os.scandir()。按模式匹配时使用 glob.glob();处理路径对象时使用 pathlib.Path.rglob()。如果需要自定义遍历策略并愿意自行实现,可以选择 os.listdir()。这些方法返回的是路径或名称,而不是文件内容;要读取或处理文件,需要另外打开相应路径。对于不存在或无法读取的起始目录,应根据所用 API 和应用程序需要处理文件系统错误。