如何使用pathlib模块在Python3中操作文件系统路径
作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
Python 3 包括 pathlib 模块 用于不可知地操作文件系统路径,无论操作系统如何。 pathlib 类似于 os.path 模块,但 pathlib 提供了比 os.path 更高级别且通常更方便的接口。
我们可以通过分层路径识别计算机上的文件。 例如,我们可能会使用以下路径识别计算机上的文件 wave.txt:/Users/sammy/ocean/wave.txt。 操作系统表示路径略有不同。 Windows 可能表示 wave.txt 文件的路径,如 C:\Users\sammy\ocean\wave.txt。
如果在您的 Python 程序中,您可能会发现 pathlib 模块很有用:在文件系统上创建或移动文件,在文件系统上列出所有匹配给定扩展名或模式的文件,或基于操作系统创建适当的文件路径关于原始字符串的集合。 虽然您可能能够使用其他工具(如 os.path 模块)来完成其中许多任务,但 pathlib 模块允许您以高度可读性和最少的数量执行这些操作的代码。
在本教程中,我们将介绍一些使用 pathlib 模块来表示和操作文件系统路径的方法。
先决条件
为了充分利用本教程,建议您熟悉 Python 3 中的编程。 您可以查看这些教程以获取必要的背景信息:
构造 Path 实例
pathlib 模块提供了几个 类,但最重要的一个是 Path 类。 Path 类的实例代表我们计算机文件系统上文件或目录的路径。
例如,以下代码实例化了一个 Path 实例,该实例表示 wave.txt 文件的部分路径:
from pathlib import Path
wave = Path("ocean", "wave.txt")
print(wave)
如果我们运行此代码,我们将收到如下输出:
Outputocean/wave.txt
from pathlib import Path 使 Path 类可用于我们的程序。 然后 Path("ocean", "wave.txt") 实例化一个新的 Path 实例。 打印输出显示 Python 在我们给它的两个路径组件之间添加了 / 的适当操作系统分隔符:"ocean" 和 "wave.txt"。
注意: 根据您的操作系统,您的输出可能与本教程中显示的示例输出略有不同。 例如,如果您运行的是 Windows,则第一个示例的输出可能类似于 ocean\wave.txt。
目前,分配给wave变量的Path对象包含一个相对路径。 换句话说,ocean/wave.txt 可能存在于我们文件系统的多个位置。 例如,它可能存在于 /Users/user_1/ocean/wave.txt 或 /Users/user_2/research/ocean/wave.txt 中,但我们没有具体说明我们指的是哪一个。 相比之下, 绝对路径 明确地指代文件系统上的一个位置。
您可以使用 Path.home() 获取当前用户主目录的绝对路径:
home = Path.home() wave_absolute = Path(home, "ocean", "wave.txt") print(home) print(wave_absolute)
如果我们运行此代码,我们将收到大致如下所示的输出:
Output/Users/sammy /Users/sammy/ocean/wave.txt
注意: 如前所述,您的输出将根据您的操作系统而有所不同。 当然,您的主目录也将不同于 /Users/sammy。
Path.home() 返回一个 Path 实例,其中包含指向当前用户主目录的绝对路径。 然后我们将这个 Path 实例和字符串 "ocean" 和 "wave.txt" 传递到另一个 Path 构造函数中,以创建到 wave.txt 的绝对路径文件。 输出显示第一行是主目录,第二行是主目录加上 ocean/wave.txt。
此示例还说明了 Path 类的一个重要特性:Path 构造函数接受字符串和预先存在的 Path 对象。
让我们更仔细地看一下 Path 构造函数中对字符串和 Path 对象的支持:
shark = Path(Path.home(), "ocean", "animals", Path("fish", "shark.txt"))
print(shark)
如果我们运行此 Python 代码,我们将收到类似于以下内容的输出:
Output/Users/sammy/ocean/animals/fish/shark.txt
shark 是我们使用 Path 对象(Path.home() 和 Path("fish", "shark.txt"))和字符串("ocean" 和 "animals")。 Path 构造函数智能地处理这两种类型的对象,并使用适当的操作系统分隔符将它们干净地连接起来,在本例中为 /。
访问文件属性
现在我们已经学习了如何构建 Path 实例,让我们回顾一下如何使用这些实例来访问有关文件的信息。
我们可以使用 name 和 suffix 属性来访问文件名和文件后缀:
wave = Path("ocean", "wave.txt")
print(wave)
print(wave.name)
print(wave.suffix)
运行此代码,我们将收到类似于以下内容的输出:
Output/Users/sammy/ocean/wave.txt wave.txt .txt
此输出显示我们路径末尾的文件名是 wave.txt,该文件的后缀是 .txt。
Path 实例还提供 with_name 函数,允许您无缝创建具有不同名称的新 Path 对象:
wave = Path("ocean", "wave.txt")
tides = wave.with_name("tides.txt")
print(wave)
print(tides)
如果我们运行它,我们将收到如下输出:
ocean/wave.txt ocean/tides.txt
代码首先构造一个 Path 实例,该实例指向一个名为 wave.txt 的文件。 然后,我们在 wave 上调用 with_name 方法以返回第二个 Path 实例,该实例指向一个名为 tides.txt 的新文件。 路径的 ocean/ 目录部分保持不变,最终路径为 ocean/tides.txt
访问祖先
有时访问包含给定路径的目录很有用。 让我们考虑一个例子:
shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent)
如果我们运行此代码,我们将收到如下所示的输出:
Outputocean/animals/fish/shark.txt ocean/animals/fish
Path 实例上的 parent 属性返回给定文件路径的最直接祖先。 在这种情况下,它返回包含 shark.txt 文件的目录:ocean/animals/fish。
我们可以连续多次访问 parent 属性以向上遍历给定文件的祖先树:
shark = Path("ocean", "animals", "fish", "shark.txt")
print(shark)
print(shark.parent.parent)
如果我们运行此代码,我们将收到以下输出:
Outputocean/animals/fish/shark.txt ocean/animals
输出与之前的输出类似,但现在我们通过第二次访问 .parent 遍历了更高的级别。 shark.txt 上两个目录是 ocean/animals 目录。
使用 Glob 列出文件
也可以使用 Path 类使用 glob 方法列出文件。
假设我们有一个如下所示的目录结构:
└── ocean
├── animals
│ └── fish
│ └── shark.txt
├── tides.txt
└── wave.txt
ocean 目录包含文件 tides.txt 和 wave.txt。 我们有一个名为 shark.txt 的文件嵌套在 ocean 目录下,一个 animals 目录和一个 fish 目录:ocean/animals/fish。
要列出 ocean 目录中的所有 .txt 文件,我们可以说:
for txt_path in Path("ocean").glob("*.txt"):
print(txt_path)
此代码将产生如下输出:
Outputocean/wave.txt ocean/tides.txt
"*.txt" glob 模式 查找所有以 .txt 结尾的文件。 由于代码示例在 ocean 目录中执行该 glob,因此它返回 ocean 目录中的两个 .txt 文件:wave.txt 和 [X150X ]。
注意: 如果您想复制此示例中显示的输出,您需要在您的计算机上模仿此处所示的目录结构。
我们也可以递归地使用 glob 方法。 要列出 ocean 目录及其所有子目录中的所有 .txt 文件,我们可以说:
for txt_path in Path("ocean").glob("**/*.txt"):
print(txt_path)
如果我们运行此代码,我们将收到如下输出:
Outputocean/wave.txt ocean/tides.txt ocean/animals/fish/shark.txt
glob 模式的 ** 部分将递归匹配此目录及其下的所有目录。 因此,我们不仅在输出中有 wave.txt 和 tides.txt 文件,而且我们还收到了嵌套在 ocean/animals/fish 下的 shark.txt 文件。
计算相对路径
我们可以使用 Path.relative_to 方法来计算相对于彼此的路径。 例如,当您想要检索长文件路径的一部分时,relative_to 方法很有用。
考虑以下代码:
shark = Path("ocean", "animals", "fish", "shark.txt")
below_ocean = shark.relative_to(Path("ocean"))
below_animals = shark.relative_to(Path("ocean", "animals"))
print(shark)
print(below_ocean)
print(below_animals)
如果我们运行它,我们将收到如下输出:
Outputocean/animals/fish/shark.txt animals/fish/shark.txt fish/shark.txt
relative_to 方法返回一个相对于给定参数的新 Path 对象。 在我们的示例中,我们计算 Path 到 shark.txt 相对于 ocean 目录,然后相对于 ocean 和 animals目录。
如果 relative_to 因为我们给它一个不相关的路径而无法计算答案,它会引发 ValueError:
shark = Path("ocean", "animals", "fish", "shark.txt")
shark.relative_to(Path("unrelated", "path"))
我们将收到从该代码引发的 ValueError 异常,如下所示:
OutputTraceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/Python3.8/pathlib.py", line 899, in relative_to
raise ValueError("{!r} does not start with {!r}"
ValueError: 'ocean/animals/fish/shark.txt' does not start with 'unrelated/path'
unrelated/path 不是 ocean/animals/fish/shark.txt 的一部分,因此 Python 无法为我们计算相对路径。
结论
pathlib 模块是 Python 标准库 的强大部分,它可以让我们在任何操作系统上快速操作文件系统路径。 在本教程中,我们学习了使用 pathlib 的一些关键实用程序来访问文件属性、使用 glob 模式列出文件以及遍历父文件和目录。
pathlib 模块公开了我们在本教程中没有介绍的其他类和实用程序。 现在您有了基线,您可以使用 pathlib 模块的文档 了解更多关于其他可用类和实用程序的信息。
如果您对使用其他 Python 库感兴趣,请查看以下教程: