redballoon 发表于 2024-3-29 01:17

Python中pathlib库的基础用法

本帖最后由 redballoon 于 2024-3-29 01:52 编辑

## 前言

`pathlib `是 Python 3.4 引入的一个库,用于处理文件路径。它提供了一种简洁、面向对象的方式来操作文件和目录路径,相比于传统的 `os `模块,`pathlib `更加易于使用和理解,也是官方推荐的使用方法。

`Pathlib `库的主要特点包括:

1. 面向对象:`Pathlib `路径对象表示文件或目录路径,并提供了一系列方法来操作这些路径。
2. 跨平台:`Pathlib `库是跨平台的,可以在不同的操作系统上工作。
3. 简洁性:相比传统的 `os.path` 模块,`Pathlib `提供了更简洁和直观的路径操作。
4. 功能丰富:`Pathlib `提供了许多用于路径操作的方法,如 `joinpath()`,`split()`, `dirname()`, `basename()`等。

对于第一次使用此模块,我们只需要导入一个**Path**即可。

## pathlib库的类介绍

**`pathlib`模块中包含了两个主要类:`Path`和`PurePath`。**

1. `Path`:表示路径的主要类,用于创建、操作和表示文件系统路径。它有一些常用的属性和方法,如 `name`(获取路径的基本名称)、`parent`(获取路径的父目录)、`exists()`(检查路径是否存在)、`is_file()`(检查路径是否为文件)、`is_dir()`(检查路径是否为目录)等。
2. `PosixPath` 和 `WindowsPath`:`Path` 的子类,分别用于处理 POSIX 和 Windows 系统的路径。它们继承了 `Path` 的属性和方法,并提供了一些特定于不同操作系统的功能。
3. `PurePath`:`Path` 的基类,用于处理纯路径,不直接与文件系统交互。它提供了基本的路径操作,但不会涉及实际的文件系统访问。
4. `PurePosixPath` 和 `PureWindowsPath`:`PurePath` 的子类,分别表示纯 POSIX 和 Windows 系统的路径。它们用于处理纯路径,不涉及实际文件系统操作。

## 导入模块

```python
from pathlib import Path
```

## 路径操作方法

### Path类方法

+ `Path.cwd()`
+ 返回一个新的表示当前目录的路径对象(和 [`os.getcwd()`](https://docs.python.org/zh-cn/3/library/os.html#os.getcwd) 返回的相同)
+ `Path.home()`
+ 返回一个表示用户家目录的新路径对象(与带 `~` 构造的 [`os.path.expanduser()`](https://docs.python.org/zh-cn/3/library/os.path.html#os.path.expanduser) 所返回的相同)。

### 常用路径属性

`pathlib`的属性通过查看源码发现是在`Path`的父类 `PurePath`中通过装饰器`@property`来让方法可以像属性一样被访问。

+ `Path.name`: 用于获取路径中的文件名部分。
+ `Path.stem`: 用于获取路径中的文件名部分但不包括文件扩展名。
+ `Path.suffix`: 用于获取路径中的文件扩展名部分。
+ `Path.suffixes`: 用于获取路径中的文件扩展名部分,但与 `Path.suffix` 不同的是,`Path.suffixes` 返回的是一个列表,包含路径中所有的文件扩展名部分,每个扩展名都包括点号 `.`。
+ `Path.root`: 用于返回路径的根部分。对于绝对路径来说,根部分就是路径的根目录 `\`。
+ `Path.parts`: 用于返回路径的各个部分组成的元组。每个部分都是路径中的一个目录或文件名。
+ `Path.anchor`: 用于返回路径的根目录部分。对于绝对路径,根目录部分就是路径的根目录,在`Windowns`中为`E:\`,在类`Unix`中为`\`。
+ `Path.parent`: 用于返回路径的父目录部分。
+ `Path.parents`: 用于返回路径的所有父目录部分,以一个可迭代的对象的形式返回。这个可迭代对象包含了路径的所有父目录,直到根目录为止。

### 常用路径方法

实例方法返回的类型是:`<class 'pathlib.WindowsPath'>`,是一种类路径类型(PathLike),它们实现了文件系统路径的常用操作,如拼接(使用 `/` 运算符)、解析和修改。这使得处理路径变得更加直观和易于理解。

**Path.stat(\*)**

+ 返回一个 [`os.stat_result`](https://docs.python.org/zh-cn/3/library/os.html#os.stat_result) 对象,其中包含有关此路径的信息,包括文件的元数据(如大小、权限、最后访问时间等)。
+ 此方法与`os.stat()`类似。

```python
file_path = Path('demo.py')
stat_info = file_path.stat()
>>> stat_info
os.stat_result(st_mode=33206, st_ino=74590868828380952, st_dev=3237859167, st_nlink=1, st_uid=0, st_gid=0, st_size=149, st_atime=1709787460, st_mtime=1709787460, st_ctime=1709787445)
>>> stat_info.st_size
149
```

**Path.exists(\*)**

+ 该方法用于检查指定路径是否存在。如果路径存在,则返回 `True`;如果路径不存在,则返回 `False`。

```python
# 创建一个 Path 对象
file_path = Path("demo.py")

# 检查路径是否存在
if file_path.exists():
    print("File exists.")
else:
    print("File does not exist.")
```

**Path.expanduser()**

+ 返回带有扩展 `~` 和 `~user` 构造的新路径,与 [`os.path.expanduser()`](https://docs.python.org/zh-cn/3/library/os.path.html#os.path.expanduser) 所返回的相同。

```python
path = Path('~/Desktop/file.txt')
expanded_path = path.expanduser()
>>> expanded_path
'C:\Users\redballoon\Desktop\file.txt'
```

**Path.glob(pattern, \*, case_sensitive=None)**

+ 用于根据指定的模式匹配文件或目录。该方法返回一个生成器,可以用于遍历满足指定模式的文件或目录。

+ <font color="red">`Path('.').glob('**/*.py')` 会递归查找当前目录及其所有子目录中的**.py**文件,而 `Path('.').glob('*/*.py')` 只会匹配当前目录下的直接子目录中的**.py**文件。</font>

```python
folder_path = Path('.')
# 查找当前目录下所有以.py结尾的文件
for file_path in folder_path.glob('*/*.py'):
    print(file_path)
```

> 备注:在一个较大的目录树中使用 "`**`" 模式可能会消耗非常多的时间。

**Path.is_dir()**

+ 用于检查指定路径是否为一个目录(文件夹)。如果路径指向一个目录,则返回 `True`;如果路径指向一个文件或者不存在的路径,则返回 `False`。

```python
my_path = Path('.').is_dir()# True
my_path = Path('demo.py').is_dir()# False
```

**Path.is_file()**

+ 用于检查指定路径是否为一个文件。如果路径指向一个文件,则返回 `True`;如果路径指向一个目录或者不存在的路径,则返回 `False`。

```python
my_path = Path('demo.py').is_file()# True
my_path = Path('.').is_file()# False
```

**Path.iterdir()**

+ 用于遍历指定目录下的所有文件和子目录。具体来说,`iterdir()` 方法返回一个迭代器(生成器),通过该迭代器(生成器)可以依次访问目录中的每个子目录项(包括文件和子目录)。
+ 子条目会以任意顺序生成,并且不包括特殊条目 `'.'` 和 `'..'`。

```python
# 指定要遍历的目录路径
directory_path = Path(".")

for item in directory_path.iterdir():
    if item.is_file():# 判断是否为文件
      print(f"File: {item.name}")
    elif item.is_dir():# 判断是否为目录
      print(f"Directory: {item.name}")
```

**Path.walk(top_down=True)**

+ 用于递归遍历指定目录下的所有文件和子目录。该方法返回一个迭代器,可以按照指定的顺序(从顶层到底层或从底层到顶层)遍历目录结构。
+ `top_down=True` 表示按照自顶向下的顺序进行遍历,默认为 `True`。如果设置为 `False`,则表示按照自底向上的顺序进行遍历。

```python
在 python 3.12 版本加入.暂不讨论
```

**Path.mkdir(parents=False, exist_ok=False)**

+ 用于创建一个目录。
+ `parents`:如果设置为 `True`,则会自动创建必要的父目录;如果设置为 `False`,则只创建最后一级目录,默认为 `False`。
+ `exist_ok`:如果设置为 `True`,当目录已经存在时不会引发异常;如果设置为 `False`,当目录已经存在时会引发 `FileExistsError`,默认为 `False`。

```python
# 创建一个名为 "new_dir" 的目录,如果目录已经存在则不引发异常
Path("new_dir").mkdir(exist_ok=True)
```

**Path.rename(target)**

+ 用于将当前路径指定的文件或目录重命名为目标路径。这个方法接受一个参数 `target`,表示重命名后的目标路径。在 Windows 上,如果 *target* 存在,则将会引发 [`FileExistsError`](https://docs.python.org/zh-cn/3/library/exceptions.html#FileExistsError)。

```python
# 创建一个名为 "old_name.txt" 的文件
Path("old_name.txt").touch()

# 将文件名从 "old_name.txt" 改为 "new_name.txt"
Path("new_name.txt").rename("new_name.txt")
```

在windowns中使用确保目标路径(target)不存在:

```python
# 创建一个名为 "old_name.txt" 的文件
Path("old_name.txt").touch()

# 确保目标路径 "new_name.txt" 不存在,然后重命名文件
if not Path("new_name.txt").exists():
    Path("old_name.txt").rename("new_name.txt")
else:
    # 如果目标路径已经存在,先删除目标路径再重命名
    Path("new_name.txt").unlink()      
    Path("old_name.txt").rename("new_name.txt")
```

**Path.replace(target)**

+ 用于将当前路径对象替换为目标路径对象。它返回一个新的Path对象,表示替换后的路径。
+ Path.replace(target)方法会将当前路径对象指向的文件或目录替换为目标路径对象指向的文件或目录。如果目标路径对象已经存在,则会被替换;如果目标路径对象不存在,则会创建一个新的文件或目录。
+ Path.rename(target)与Path.replace(target)的区别:
+ `p.rename(target)` 方法是直接在当前路径对象上进行重命名操作,而 `Path.replace(target)` 方法是创建一个新的 `Path` 对象来替换目标路径。

```python
# 创建一个名为 "source.txt" 的文件和一个名为 "target.txt" 的文件
Path("source.txt").touch()
Path("target.txt").touch()

# 创建 Path 对象
source_path = Path("source.txt")
target_path = Path("target.txt")
# 将 source.txt 替换为 target.txt
replaced_path = source_path.replace(target_path)
# 打印被替换的文件路径
print(f"被替换的文件路径: {replaced_path}")
print(f"source.txt 是否存在: {source_path.exists()}")
print(f"target.txt 是否存在: {target_path.exists()}")
```

**Path.absolute()**

+ 用于获取指定路径对象的绝对路径。

```python
# 创建一个相对路径对象
relative_path = Path("my_folder/my_file.txt")
# 获取相对路径对象的绝对路径
absolute_path = relative_path.absolute()
>>> absolute_path
'E:\pythonProjects\pythonProject\my_folder\my_file.txt'
```

**Path.resolve(strict=False)**

+ 于获取指定路径对象的绝对路径,并解析可能存在的符号链接(软链接)。
+ `absolute()`与`resolve()`的区别:
+ `absolute()` 方法不会解析符号链接,而 `resolve(strict=False)` 方法会尝试解析符号链接。如果需要处理符号链接并获取最终的绝对路径,可以使用 `resolve(strict=False)` 方法;如果只需要获取绝对路径而不关心符号链接,则可以使用 `Path.absolute()` 方法。

```python
# 创建一个带符号链接的路径对象
symbolic_link_path = Path("my_folder/my_symbolic_link")
# 获取解析后的绝对路径
resolved_path = symbolic_link_path.resolve()
>>> resolved_path
'E:\pythonProjects\pythonProject\my_folder\my_symbolic_link'
```

**Path.rmdir()**

+ 用于删除指定的空目录。它会删除路径对象所指向的目录,前提是该目录必须为空,否则会引发OSError异常。

```python
directory_to_delete = Path("my_folder")# # 要删除的目录
directory_to_delete.rmdir()## 删除目录
```

**Path.touch(exist_ok=True)**

+ 用于创建一个空文件。如果文件已经存在,则不会引发异常,除非设置了exist_ok参数为False,此时会引发FileExistsError异常。

```python
Path("my_file.txt").touch()
```

**Path.unlink(missing_ok=False)**

+ 用于删除指定的文件或符号链接。
+ 如果给定路径是一个文件,它将永久删除该文件;如果给定路径是一个目录,将引发 `IsADirectoryError` 异常。
+ 如果文件不存在且 `missing_ok=False`(默认值),将引发 `FileNotFoundError` 异常;如果文件不存在且 `missing_ok=True`,不会引发异常,函数将直接返回。

```python
# 要删除的文件
file_to_delete = Path("my_file.txt")

try:
    # 删除文件
    file_to_delete.unlink(missing_ok=True)
    print(f"文件 {file_to_delete} 删除成功")
except OSError as e:
    print(f"删除文件 {file_to_delete} 失败: {e}")
```

**Path.joinpath(*other)**

+ 用于将多个路径组件连接成一个新的路径对象。

+ 需要注意的是,`joinpath()` 只是简单地连接路径组件,并不会检查路径是否真实存在。

```python
# 连接相对路径
p1 = Path('dir1/dir2')
p2 = p1.joinpath('file.txt')
print(p2)# 输出: dir1/dir2/file.txt

# 连接多个路径组件
p = Path('folder1', 'folder2', 'demo.txt').joinpath()
print(p)# 输出: folder1\folder2\demo.txt
```

## pathlib对应的os模块的工具

以下是一个映射了 `os` 与 `PurePath``Path` 对应相同的函数的表。

> 备注:以下函数/方法对并不全都是等价的。 在它们之中,有的虽然具有相互重叠的使用场景,但其语义有所不同。 这包括 `os.path.abspath()`与 `Path.absolute()`, `os.path.relpath()`与 `PurePath.relative_to()`。

![](https://img1.sycdn.imooc.com//6117c4520001d1fa07650665.jpg)

![](https://img1.sycdn.imooc.com//6117c4660001f3c507630417.jpg)

020lx 发表于 2024-3-29 01:25

用于处理文件路径

shojnhv 发表于 2024-3-29 06:14

学习了,感谢分享

crlong33 发表于 2024-3-29 07:03

66666666666666666666

chlryg 发表于 2024-3-29 09:02

这是第三方库还是自有库?

coder126 发表于 2024-3-29 10:48

学习,学习。分享{:1_921:}

luxingyu329 发表于 2024-3-29 11:14

chlryg 发表于 2024-3-29 09:02
这是第三方库还是自有库?

这个是自带的标准类库

O2H2O 发表于 2024-3-30 13:41

好奇同样是标准库为啥又新起炉灶搞一个呢……
页: [1]
查看完整版本: Python中pathlib库的基础用法