什么是pathlib?

pathlib是从Python3.4版本开始引入的一个路径操作的基本库,为了更加方便使用者创建和操作文件路径。

pathlib没出来之前,我们都需要使用str或者os.path获取路径,但是有了pathlib之后,我们会获得一个名为Path的类对象,拥有许多可以对路径操作的方法,比起之前使用os模块更加方便。

使用前需要先导入

1
from pathlib import Path

转化为Path对象

假如你有一个字符串路径,你想要将它转化为Path对象,只需要将其放入Path中,他会根据操作系统的类型自动将其转化为合法的路径(即使你的路径不规范)

1
2
3
4
path = "D:///Python_ProjectHouse\\\Hardcore_Python\\\print_format.py"

path = Path(path)
path # WindowsPath('D:/Python_ProjectHouse/Hardcore_Python/print_format.py')

在上面的例子中,放入了一个奇怪的路径格式,Path模块直接就将其转化为了WindowsPath对象,且路径问题也被修复了

路径获取

最常用的就是获取当前文件、文件夹的路径

Path内实现了__str__的方法,因此可以很容易转化为字符串。

1
2
3
4
5
6
# 获取当前工作目录的绝对路径
print(Path.cwd()) # d:\Code\Python
# 获得当前电脑的用户路径
print(Path.home()) # C:\Users\zhang
# 获取当前文件的路径
print(Path(__file__)) # d:\Code\Python\pathlib_demo.py

如果你输入的是一个相对路径,那么会返回一个绝对路径

1
2
3
4
# 获得绝对路径
path = Path("pathlib_demo.py")
print(path.resolve()) # d:\Code\Python\pathlib_demo.py
print(path.absolute()) # d:\Code\Python\pathlib_demo.py

如果输入一个绝对路径,也可以使用下面的方法获得相对路径

children.relative_to(father)方法是指children相对于father的路径

1
2
path = Path("pathlib_demo.py")
print(path.absolute().relative_to(Path.cwd())) # pathlib_demo.py

父与子路径

有了路径之后我们为了实现路径的拼接,有时候需要获取上一级目录的路径,Path对象也是可以做到的。

找到父路径使用的是parent或者parents属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
path = path.absolute()
# 获得上一级的路径
print(path.parent) # d:\Code\Python
# 可以打印出所有的父路径 最上能到盘符
print([i for i in path.parents]) # [WindowsPath('d:/Code'), WindowsPath('d:/')]
# 获取路径组成
print(path.parts) # ('d:\\', 'Code', 'Python', 'pathlib_demo.py')
# 获取路径的根目录
print(path.drive) # d:
# 获取路径的根目录
print(path.root) # \
# 获取路径的名称
print(path.anchor) # d:\

找到当前目录下的所有文件路径,可以使用iterdir(),但是他不会递归查找子文件下的文件。

如果想要筛选文件的类型,使用gloab()rglob()(会递归寻找子文件下的文件)是更好的选择。

1
2
3
4
5
6
# 列出所有子路径 不会递归搜索子文件夹
print([i for i in path.iterdir()])
# Path.glob() - 扫描子路径 不会递归搜索子文件夹
# Path.rglob() - 递归扫描子路径 会递归搜索子文件夹 可以指定文件类型
print([i for i in path.glob("*.py")],len([i for i in path.glob("*.py")]))
print([i for i in path.rglob("*")])

路径拼接

Path对象相比os.path.join()方法拼接路径要方便得多,直接在字符串和Path对象之间使用/即可拼接。

如果想要更加的直观,可以使用Path.joinpath()的方法。

1
2
3
4
5
6
7

path = Path.cwd() # d:\Code\Python
print(path / "test" / "test1") # d:\Code\Python\test\test1

print(path.joinpath("test", "test1")) # d:\Code\Python\test\test1

print(path.joinpath("test/test1")) # d:\Code\Python\test\test1

路径合法检查

获得了一个路径,Path会自动合法化路径,但是不会检查路径是否存在,这时候需要自行判断是否为存在。

使用判断方法后会根据情况返回一个bool值

1
2
3
4
5
6
7
8
9
10
# 判断路径是否存在
print(path.exists()) # true
# 判断是否是文件
print(path.is_file()) # true
# 判断是否是目录
print(path.is_dir()) # false
# 判断是否是绝对路径
print(path.is_absolute()) # false
# 判断是否是软链接
print(path.is_symlink()) # false

文件属性

如果当前路径为文件路径且存在的话,Path还提供了一些方法来获得文件的基本属性

文件的具体信息使用的是stat()方法,他会返回文件的所有属性信息,常用的有:

  • st_size 文件大小 单位是byte
  • st_ctime 在 Windows 系统中,这是文件创建的时间。单位是秒
  • st_mtime 文件最后修改的时间,单位是秒
  • st_atime 文件最后访问的时间,单位是秒

获得时间大小都是从 1970 年 1 月 1 日 00:00:00 UTC 开始计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 获得文件名
print(path.name)
# 获得文件后缀
print(path.suffix)
# 获得文件名不带后缀
print(path.stem)
# 获得文件具体信息
print(path.stat())
# 获取文件大小 单位byte
print(path.stat().st_size)
# 获取文件创建时间 时间戳
print(path.stat().st_ctime)
# 获取文件修改时间 时间戳
print(path.stat().st_mtime)
# 获取文件访问时间 时间戳
print(path.stat().st_atime)

要注意的是stat()中返回的时间是时间戳的形式,如果要格式化,可以使用datetime模块

1
2
3
# 转化为规则时间
from datetime import datetime
print(datetime.fromtimestamp(path.stat().st_ctime)) # 2024-04-10 18:13:35.900849

还有些不常用的操作,比如修改文件名和文件后缀(只是修改了Path的值,真实的文件名和后缀没有被修改,要真正修改需要使用path.rename()方法)

1
2
3
4
# 修改文件后缀
print(path.with_suffix(".txt")) # d:\Code\Python\pathlib_demo.txt
# 修改文件名
print(path.with_name("new_name.py")) # d:\Code\Python\new_name.py

文件操作

Path不仅支持对现有路径的操作,支持使用touch()创建一个文件或使用mkdir()创建一个目录

删除目录之前,最好要使用path.exists()来判断一下当前文件/文件夹是否存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建文件
path = Path("test.txt")
path.touch()
# 删除文件
path.unlink()

path = Path("test")
# 创建目录 目录不能存在 存在会报错
path.mkdir()
# 删除目录
path.rmdir()
# 重命名
path = Path("test")
path.rename("test1")
# 转移
path = Path("test1")
path.replace("test")

打开和写入文件

Path还支持打开文件,而且还支持with这种上下文打开的方式。

常见的打开模式都是支持的

  • w 写入 会覆盖之前的记录
  • a 追加 在原记录之下追加信息
  • r 读取 只读取文件

写入和读取都支持write_text()write_bytes()这两种方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 打开文件
path = Path("test.txt")

# Path.write_text() - 写入文件 会覆盖原文件
path.write_text("test text")
# Path.read_text() - 读取文件 文本
print(path.read_text()) # test text
# Path.write_bytes() - 写入文件 会覆盖原文件
path.write_bytes(b"test bytes")
# Path.read_bytes() - 读取文件 二进制
print(path.read_bytes()) # b"test bytes"

# Path.open() - 打开文件
with path.open("w") as f:
f.write("hello world")

with path.open("r") as f:
print(f.read()) # hello world