pathlib模块

pathlib: 是python内置模块,用来处理文件及目录操作。 相比于os.path,它将路径包装成对象,使用起来更符合直觉,用这一个模块就基本上可以完成所有对文件及目录的增删改查,遍历,重命名,查找等各种操作。
使用此模块时,我们主要使用Path类,它提供了绝大部分的属性和方法来实现我们的日常操作。并且它内部自动根据python的运行环境来决定适应于不同操作系统的具体操作和特征。

创建Path对象时,我们可以通过传递一个路径字符串来创建,可以创建相对路径,也可以创建绝对路径。"."表示当前工作目录,当然属于相对路径。我们可以使用resolve函数将相对路径转化成绝对路径。

from pathlib import Path
path = Path(".")  # 当前工作目录
print(repr(path))

path = Path("./world")  # 等价于"world"
print(repr(path))

print(repr(path.resolve()))

path = Path("world", "europe")  # 还可以传递多个段作为参数,生成的Path对象将自动拼接各个段。
print(repr(path))

输出结果:

WindowsPath('.')
WindowsPath('world')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world')
WindowsPath('world/europe')

Path.home(): 获得家目录Path对象
Path.cwd(): 获得当前工作目录Path对象

from pathlib import Path

print(repr(Path.home()))  # 系统家目录

cwd = Path.cwd()
print(repr(cwd))  # 当前工作目录

path = cwd / "world" / "europe"  # Path对象与字符串表示的路径拼接
print(repr(path))

path = cwd / Path("world", "europe")  # Path对象与Path对象拼接,但后者得是相对路径。
print(repr(path))

输出结果:

WindowsPath('C:/Users/user')
WindowsPath('F:/RolandWork/PythonProjects/studyPython')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe')

Path对象常用属性
PurePath.parts: 反回路径中的各个段,包括根盘符(如果有),文件名(如果有)。

from pathlib import Path

path = Path("world", "europe", "main.py")  # 还可以传递多个段作为参数,生成的Path对象将自动拼接各个段。
print(repr(path))
print(path.parts)

path = path.resolve()
print(repr(path))
print(path.parts)

输出结果:

WindowsPath('world/europe/main.py')
('world', 'europe', 'main.py')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe/main.py')
('F:\\', 'RolandWork', 'PythonProjects', 'studyPython', 'world', 'europe', 'main.py')

查找上级目录: parent, anchor, drive, root, parents 等属性。

from pathlib import Path

path = Path("world", "europe", "main.py")  # 还可以传递多个段作为参数,生成的Path对象将自动拼接各个段。
print(repr(path))
print(repr(path.parent))
print(repr(path.anchor))
print(repr(path.drive))
print(repr(path.root))
# print(path.parents)
for item in path.parents:
    print(repr(item))

print("-" * 25, "分隔线", "-" * 25)
path = path.resolve()
print(repr(path))
print(repr(path.parent))
print(repr(path.anchor))
print(repr(path.root))
# print(path.parents)
for item in path.parents:
    print(repr(item))

输出结果:

WindowsPath('world/europe/main.py')
WindowsPath('world/europe')
''
''
''
WindowsPath('world/europe')
WindowsPath('world')
WindowsPath('.')
------------------------- 分隔线 -------------------------
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe/main.py')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe')
'F:\\'
'\\'
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world/europe')
WindowsPath('F:/RolandWork/PythonProjects/studyPython/world')
WindowsPath('F:/RolandWork/PythonProjects/studyPython')
WindowsPath('F:/RolandWork/PythonProjects')
WindowsPath('F:/RolandWork')
WindowsPath('F:/')

文件名,扩展名属性: name, suffix, suffixes, stem
name为文件名(包含扩展名), suffix是扩展名,suffixes是多个扩展名,用列表返回。stem是去掉扩展名,即文件名但不包含扩展名。

from pathlib import Path

path = Path('my/library/setup.py')
print(path.name)  # setup.py
print(path.suffix)  # .py
print(path.suffixes)  # ['.py']
print(path.stem)  # setup

print("-" * 25, "分隔线", "-" * 25)

path = Path('my/library.tar.gz')
print(path.name)  # library.tar.gz
print(path.suffix)  # .gz
print(path.suffixes)  # ['.tar', '.gz']
print(path.stem)  # library.tar

输出结果:

setup.py
.py
['.py']
setup
------------------------- 分隔线 -------------------------
library.tar.gz
.gz
['.tar', '.gz']
library.tar

相对路径与绝对路径
Path.absolute(): 将相对路径转成绝对路径,但不去处理路径中可能存在的".."。
Path.resolve(strict=False): 也将相对路径转成绝对路径,并且会处理路径中存在的"..",并且,当strict=True时,会实际检查路径是否存在,不存在则抛异常。

from pathlib import Path

path = Path('./world/../europe/main.py')
print(path.absolute())  # F:\RolandWork\PythonProjects\studyPython\world\..\europe\main.py
print(path.resolve())  #  F:\RolandWork\PythonProjects\studyPython\europe\main.py
print(path.resolve(strict=True))  # 系统找不到指定的路径。: 'F:\\RolandWork\\PythonProjects\\studyPython\\europe\\main.py'

PurePath.relative_to(other, walk_up=False): 计算此路径相对于 other 所表示路径的版本。 如果不可计算,则引发 ValueError。当 walk_up 为(默认的)假值时,路径必须以 other 开始。 当参数为真值时,可能会添加 .. 条目以形成相对路径。

from pathlib import Path

path = Path('a/b/c/d/e')
print(path.relative_to(Path('a/b/')))  # c\d\e

PurePath.is_absolute(): 返回此路径是否为绝对路径。如果路径同时拥有驱动器符与根路径, 则将被认作绝对路径(在windows系统中)。

from pathlib import Path

path = Path("main.py")
print(path.is_absolute())  # False
print(path.resolve().is_absolute())  # True

PurePath.is_relative_to(other): 返回此路径是否相对于 other 的路径。

from pathlib import Path

path = Path(".").resolve()
other_path = path.parent.parent
print(path)
print(other_path)

print(path.is_relative_to(other_path))

输出结果:

F:\RolandWork\PythonProjects\studyPython
F:\RolandWork
True

PurePath.as_posix() : 返回使用正斜杠(/)的路径字符串

from pathlib import Path

path = Path('.')
path = path.resolve()
print(path)  # F:\RolandWork\PythonProjects\studyPython
print(path.as_posix())  # F:/RolandWork/PythonProjects/studyPython

输出结果:

F:\RolandWork\PythonProjects\studyPython
F:/RolandWork/PythonProjects/studyPython

PurePath.joinpath(*pathsegments): 调用此方法等同于依次将路径与给定的每个 pathsegments 组合到一起。

from pathlib import Path

path = Path('.')
path = path.resolve()
print(path)

print(path / "abc" / "main.py")
print(path.joinpath("abc", "main.py"))

输出结果:

F:\RolandWork\PythonProjects\studyPython
F:\RolandWork\PythonProjects\studyPython\abc\main.py
F:\RolandWork\PythonProjects\studyPython\abc\main.py

修改文件名或扩展名
PurePath.with_name(name): 返回一个新的路径并修改 name。如果原本路径没有 name,ValueError 被抛出
PurePath.with_stem(stem): 返回一个带有修改后 stem 的新路径。 如果原路径没有名称,则会引发 ValueError
PurePath.with_suffix(suffix): 返回一个新的路径并修改 suffix。如果原本的路径没有后缀,新的 suffix 则被追加以代替。如果 suffix 是空字符串,则原本的后缀被移除

from pathlib import Path

path = Path('.').resolve() / "main.py"
print(path)

print(path.with_name("abc.txt"))
print(path.with_stem("abc"))
print(path.with_suffix(".txt"))

输出结果:

F:\RolandWork\PythonProjects\studyPython\main.py
F:\RolandWork\PythonProjects\studyPython\abc.txt
F:\RolandWork\PythonProjects\studyPython\abc.py
F:\RolandWork\PythonProjects\studyPython\main.txt

读写文件
Path.open(mode='r', buffering=-1, encoding=None, errors=None, newline=None): 打开路径指向的文件,就像内置的 open() 函数所做的一样。
Path.read_text(encoding=None, errors=None, newline=None): 以字符串形式返回路径指向的文件的解码后文本内容。文件先被打开然后关闭。有和 open() 一样的可选形参。
Path.read_bytes(): 以字节对象的形式返回路径指向的文件的二进制内容。
Path.write_text(data, encoding=None, errors=None, newline=None): 将文件以文本模式打开,写入 data 并关闭。
Path.write_bytes(data):将文件以二进制模式打开,写入 data 并关闭。

重命名与删除
对于文件或者目录,都使用相同的函数进行操作。文件的移动其实就是这里面的"重命名"的功能。面文件或目录的删除,则使用unlink。为了更加清晰的区分,移除目录时可改用rmdir函数。
Path.rename(target): 将此文件或目录重命名为给定的 target,并返回一个新的指向 target 的 Path 实例。
在 Windows 上,如果 target 存在,则会引发 FileExistsError。 target 可以是一个字符串或者另一个路径对象。
目标路径可能为绝对或相对路径。 相对路径将被解读为相对于当前工作目录,而 不是 相对于 Path 对象的目录。

Path.replace(target):将此文件或目录重命名为给定的 target,并返回一个新的指向 target 的 Path 实例。 如果 target 指向一个现有文件或空目录,则它将被无条件地替换。
目标路径可能为绝对或相对路径。 相对路径将被解读为相对于当前工作目录,而 不是 相对于 Path 对象的目录。

下面代码先将test_move.py文件从world目录移到外层,又从外层移回world目录下。 可见,rename和replace都可以达到移动文件的目的,但当目标文件已经存在时,rename会抛异常,而replace则静默替换。

from pathlib import Path

print(Path("world/test_move.py").rename("test_move.py"))  # test_move.py
print(Path("test_move.py").replace("world/test_move.py"))  # world\test_move.py

Path.rmdir(): 移除此目录(而不是文件)。此目录必须为空的。
Path.unlink(missing_ok=False): 移除文件。如果路径指向目录,则用 Path.rmdir() 代替。如果 missing_ok 为假值(默认),则如果路径不存在将会引发 FileNotFoundError。为真值时,会忽略异常。

复制文件
pathlib模块没有直接提供复制文件的操作。所以可能我们更倾向于调用shutil模块里的复制方法。
如果我们想通过Path对象的方法自己实现复制,可以参考下面代码:

from pathlib import Path
source = Path("shopping_list.md")
destination = source.with_stem("shopping_list_02")
destination.write_bytes(source.read_bytes())

模式语言: 一些通匹配符,用来匹配路径
**: 匹配任意数量目录分段或文件,包括零个。
*:用于区配分段时,匹配一个文件或目录分段。 当用在分段中时,匹配任意数量的非分隔符型字符("/"),包括零个。
?: 匹配一个不是分隔符的字符。
[seq]: 匹配在 seq 中的一个字符
[!seq]: 匹配不在 seq 中的一个字符。
对于字面值匹配,请将元字符用方括号括起来。 例如,"[?]" 将匹配字符 "?"。

** 通配符将启用递归 glob。 下面是几个例子:
**/*: 任何具有至少一个分段的路径。
**/*.py:最后部分以 ".py" 结尾的任意路径。
assets/**:以 "assets/" 开头的任意路径。也可以匹配assets路径本身。
assets/**/*:以 "assets/" 开头,但不包括 "assets/" 本身的任意路径。

模式匹配函数
PurePath.full_match(pattern, *, case_sensitive=None): 将此路径与所提供的 glob 样式匹配。完全匹配成功,则返回True,否则返回False
PurePath.match(pattern, *, case_sensitive=None): 方法与 full_match() 类似,不支持递归通配符 "**" (将视为非递归的 "*"),并且如果提供了一个相对格式,则将从右开始匹配。

from pathlib import Path

print(Path('a/b.py').match('*.py'))  # True
print(Path('/a/b/c.py').match('b/*.py'))  # True
print(Path('/a/b/c.py').match('/a/*/*.py'))  # True
print(Path('/a/b/c.py').match('/a/**/*.py'))  # True # **会当成*
print(Path('/a/b/c.py').match('a/*.py'))  # False
from pathlib import Path

Path('a/b.py').full_match('a/*.py')  # True
Path('a/b.py').full_match('*.py')  # False
Path('/a/b/c.py').full_match('/a/**')  # True
Path('/a/b/c.py').full_match('**/*.py')  # True

查询文件类型和状态
Path.stat(*, follow_symlinks=True): 返回一个 os.stat_result 对象,其中包含有关此路径的信息,就像 os.stat()。 结果会在每次调用此方法时被查找。

from pathlib import Path

path = Path('main.py')
res = path.stat()
print(res.st_size)  # 894
print(res.st_mtime)  # 1739158769.6915874

Path.exists(*, follow_symlinks=True): 检查文件或目录是否存在。

from pathlib import Path

print(Path('main.py').exists())  # True
print(Path('a/b/c').exists())  # False

Path.is_file(*, follow_symlinks=True): 判断一个路径是不是文件。
Path.is_dir(*, follow_symlinks=True): 判断一个路径是不是目录。

from pathlib import Path

print(Path('main.py').is_file())  # True
print(Path('main.py').is_dir())  # False
print(Path('abc.py').is_file())  # False  # 文件不存在。

print(Path('a/b/c').is_file())
print(Path('a/b/c').is_dir())  # False 是目录但不存在
print(Path('.').is_dir())   # True 是目录,并且存在。

Path.samefile(other_path): 返回other_path对象指向的目录或文件是否与当前path对象相同,是返回True,否则False。 或任何一个文件不存在,则抛异常。

from pathlib import Path

path = Path("main.py")
print(path.samefile("hello.txt"))  # False

读取和遍历目录
Path.iterdir(): 当路径指向一个目录时,产生该路径下的对象的路径

from pathlib import Path

path = Path("world")
for child in path.iterdir():
    print(child)
    
print("-" * 25, "分隔线", "-" * 25)

path = Path("world").resolve()
for child in path.iterdir():
    print(child)

输出结果:

world\africa
world\europe
world\test_move.py
world\__init__.py
world\__pycache__
------------------------- 分隔线 -------------------------
F:\RolandWork\PythonProjects\studyPython\world\africa
F:\RolandWork\PythonProjects\studyPython\world\europe
F:\RolandWork\PythonProjects\studyPython\world\test_move.py
F:\RolandWork\PythonProjects\studyPython\world\__init__.py
F:\RolandWork\PythonProjects\studyPython\world\__pycache__

Path.glob(pattern, *, case_sensitive=None, recurse_symlinks=False): 解析相对于此路径的通配符 pattern,产生所有匹配的文件或目录

from pathlib import Path

path = Path("world")
for item in path.glob("europe/*"):
    print(item)

输出结果:

world\europe\greece.py
world\europe\norway.py
world\europe\spain.py
world\europe\__init__.py
world\europe\__pycache__

Path.rglob(pattern, *, case_sensitive=None, recurse_symlinks=False): 递归地对相对于此路径 pattern 执行 glob 通配。 这类似于调用 Path.glob() 时在 pattern 之前加上 "**/"。
下面示例演示了 glob() 与 rglob() 的不同效果。

from pathlib import Path

path = Path("world")
for item in path.glob("*.py"):
    print(item)

print("-" * 25, "分隔线", "-" * 25)

# glob通过**来实现递规
for item in path.glob("**/*.py"):
    print(item)

print("-" * 25, "分隔线", "-" * 25)

path = Path("world")
for item in path.rglob("*.py"):
    print(item)

输出结果:

world\test_move.py
world\__init__.py
------------------------- 分隔线 -------------------------
world\test_move.py
world\__init__.py
world\africa\zimbabwe.py
world\africa\__init__.py
world\europe\greece.py
world\europe\norway.py
world\europe\spain.py
world\europe\__init__.py
------------------------- 分隔线 -------------------------
world\test_move.py
world\__init__.py
world\africa\zimbabwe.py
world\africa\__init__.py
world\europe\greece.py
world\europe\norway.py
world\europe\spain.py
world\europe\__init__.py

Path.walk(top_down=True, on_error=None, follow_symlinks=False): 通过对目录树自上而下或自下而上的遍历来生成其中的文件和目录名。该函数功能类似于os.walk() 。
对于目录树中的每个目录该方法会产生一个 3 元组 (dirpath, dirnames, filenames)。
dirpath 是指向当前正被遍历到的目录的 Path,dirnames 是由表示 dirpath 中子目录名称的字符串组成的列表,filenames 是由表示 dirpath 中非目录文件名称的字符串组成的列表。 要获取 dirpath 中文件或目录的完整路径 ,可使用 dirpath / name。 这些列表是否排序取决于具体的文件系统。
由于无法删除非空目录,下面代码演示如何删除整个目录及其所有子目录。
遍历由下自上,这样可以先删除最内层目录里所有文件,然后移除内层目录,逐步向外层递进删除。最终删除整个目录。

for root, dirs, files in top.walk(top_down=False):
    for name in files:
        (root / name).unlink()
    for name in dirs:
        (root / name).rmdir()

创建文件和目录
Path.touch(mode=0o666, exist_ok=True): 使用给定的路径创建文件。 如果文件已存在,则当 exist_ok 为真值时函数将成功执行(并且其修改时间将更新为当前时间),在其他情况下则会引发 FileExistsError。
这个方法主要是当我们需要创建空文件时使用,否则我们更倾向于使用 open(), write_text() 和 write_bytes() 方法来创建文件。
Path.mkdir(mode=0o777, parents=False, exist_ok=False): 使用给定的路径新建目录。 如果路径已存在,且exist_ok 为False, 则会引发 FileExistsError。
如果 parents 为真值,任何找不到的父目录都会伴随着此路径被创建。
如果 parents 为假值(默认),则找不到的父级目录会引发 FileNotFoundError。

posted @   RolandHe  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示