—— pathlib:面向对象的路径管理
from pathlib import Path
# 创建 Path 对象
p = Path("/home/user/docs/report.txt")
print(p) # /home/user/docs/report.txt
print(type(p)) # <class 'pathlib.PosixPath'>
# 路径各部分
print(p.anchor) # /
print(p.parent) # /home/user/docs
print(p.name) # report.txt
print(p.stem) # report
print(p.suffix) # .txt
print(p.suffixes) # ['.txt']
print(p.parts) # ('/', 'home', 'user', 'docs', 'report.txt')
# 当前目录与用户目录
print(Path.cwd()) # 当前工作目录
print(Path.home()) # 用户主目录
from pathlib import Path
# / 运算符拼接路径(pathlib 特色!)
base = Path("/home/user")
full = base / "docs" / "report.txt"
print(full) # /home/user/docs/report.txt
# 也可以用 joinpath
full2 = base.joinpath("docs", "report.txt")
# 修改路径各部分
p = Path("report.txt")
print(p.with_suffix(".md")) # report.md
print(p.with_name("summary.md")) # summary.md
print(p.with_stem("final")) # final.txt (Python 3.9+)
# 相对路径
p = Path("/home/user/docs/report.txt")
print(p.relative_to(Path("/home/user"))) # docs/report.txt
# resolve() 获取绝对路径(解析 .. 和 .)
print(Path("../docs/./report.txt").resolve())
from pathlib import Path
p = Path("/home/user/docs/report.txt")
# 存在性检查
p.exists() # 是否存在
p.is_file() # 是否为文件
p.is_dir() # 是否为目录
p.is_symlink() # 是否为符号链接
# 文件属性
if p.exists():
print(p.stat()) # os.stat_result 对象
print(p.stat().st_size) # 文件大小(字节)
print(p.stat().st_mtime) # 修改时间戳
print(p.owner()) # 所有者
print(p.group()) # 所属组
print(p.chmod(0o755)) # 修改权限
from pathlib import Path
# iterdir - 列出直接子项
for child in Path(".").iterdir():
print(child.name)
# glob - 模式匹配
for py_file in Path(".").glob("*.py"):
print(py_file)
# rglob - 递归匹配(子目录也搜索)
for py_file in Path(".").rglob("*.py"):
print(py_file)
# ** 通配符
for f in Path(".").glob("src/**/*.py"):
print(f)
# 常用过滤
def find_large_files(directory, min_size_mb=10):
"""查找大于指定大小的文件"""
dir_path = Path(directory)
min_size = min_size_mb * 1024 * 1024
for f in dir_path.rglob("*"):
if f.is_file() and f.stat().st_size >= min_size:
size_mb = f.stat().st_size / (1024 * 1024)
yield f, round(size_mb, 2)
# 统计目录下各类文件数量
from collections import Counter
ext_counter = Counter(
f.suffix for f in Path(".").rglob("*") if f.is_file()
)
for ext, count in ext_counter.most_common(10):
print(f"{ext or '无扩展名'}: {count}")
from pathlib import Path
# 创建目录
Path("new_dir").mkdir() # 已存在会报错
Path("a/b/c").mkdir(parents=True, exist_ok=True) # 递归创建,已存在不报错
# 创建文件
p = Path("hello.txt")
p.write_text("Hello, World!", encoding="utf-8")
p.write_bytes(b"Binary data")
# 读取文件
text = p.read_text(encoding="utf-8")
data = p.read_bytes()
# 追加内容
with p.open("a", encoding="utf-8") as f:
f.write("\nAppended line")
# 删除
p.unlink() # 删除文件
p.unlink(missing_ok=True) # 不存在不报错(Python 3.8+)
# 删除目录
Path("empty_dir").rmdir() # 只能删空目录
# 删除非空目录需要 shutil
import shutil
shutil.rmtree("non_empty_dir")
# 重命名/移动
p.rename("new_name.txt")
p.replace("existing.txt") # 覆盖已存在的目标
from pathlib import Path
import re
import tempfile
def batch_rename(directory, pattern, replacement, dry_run=True):
"""
批量重命名文件
pattern: 正则匹配模式
replacement: 替换字符串
dry_run: True=只预览不执行
"""
dir_path = Path(directory)
renamed = 0
for f in sorted(dir_path.iterdir()):
if not f.is_file():
continue
new_name = re.sub(pattern, replacement, f.name)
if new_name != f.name:
new_path = f.parent / new_name
if dry_run:
print(f"[预览] {f.name} → {new_name}")
else:
f.rename(new_path)
print(f"[执行] {f.name} → {new_name}")
renamed += 1
print(f"\n共 {'预览' if dry_run else '重命名'} {renamed} 个文件")
return renamed
# 示例1: 将空格替换为下划线
# batch_rename("./photos", r' ', r'_')
# 示例2: 文件名前加日期前缀
# batch_rename("./docs", r'^(.*)$', r'2026-05-19-\1')
# 示例3: 统一扩展名为小写
# batch_rename("./files", r'\.JPG$', r'.jpg')
# 创建100个测试文件并重命名
def demo_batch_rename():
with tempfile.TemporaryDirectory() as tmpdir:
dir_path = Path(tmpdir)
# 创建100个测试文件
for i in range(1, 101):
(dir_path / f"IMG_{i:04d} .JPG").write_text("")
# 预览重命名
print("=== 预览 ===")
count = batch_rename(dir_path, r' ', r'_', dry_run=True)
assert count == 100
# 执行重命名
print("\n=== 执行 ===")
count = batch_rename(dir_path, r' ', r'_', dry_run=False)
# 验证
files = list(dir_path.iterdir())
assert all(' ' not in f.name for f in files)
print("\n✅ 批量重命名验证通过")
#!/usr/bin/env python3
"""第08课 路径操作验证"""
from pathlib import Path
import tempfile
import re
def test_path_parts():
"""路径分解测试"""
p = Path("/home/user/docs/report.txt")
assert p.name == "report.txt"
assert p.stem == "report"
assert p.suffix == ".txt"
print("✅ 路径分解测试通过")
def test_path_join():
"""路径拼接测试"""
base = Path("/home/user")
full = base / "docs" / "report.txt"
assert str(full) == "/home/user/docs/report.txt"
assert full.with_suffix(".md") == Path("/home/user/docs/report.md")
print("✅ 路径拼接测试通过")
def test_file_ops():
"""文件操作测试"""
with tempfile.TemporaryDirectory() as tmpdir:
p = Path(tmpdir) / "test.txt"
p.write_text("Hello", encoding="utf-8")
assert p.read_text(encoding="utf-8") == "Hello"
assert p.is_file()
assert p.stat().st_size == 5
p.unlink()
assert not p.exists()
print("✅ 文件操作测试通过")
def test_dir_ops():
"""目录操作测试"""
with tempfile.TemporaryDirectory() as tmpdir:
base = Path(tmpdir)
(base / "a" / "b").mkdir(parents=True)
(base / "a" / "file.txt").write_text("test")
assert (base / "a" / "b").is_dir()
assert (base / "a" / "file.txt").is_file()
print("✅ 目录操作测试通过")
def test_batch_rename():
"""批量重命名测试"""
with tempfile.TemporaryDirectory() as tmpdir:
dir_path = Path(tmpdir)
# 创建测试文件
for i in range(1, 101):
(dir_path / f"file_{i:03d} .txt").write_text("")
# 重命名:去空格
for f in dir_path.iterdir():
new_name = f.name.replace(" ", "_")
f.rename(f.parent / new_name)
# 验证
files = list(dir_path.iterdir())
assert len(files) == 100
assert all(' ' not in f.name for f in files)
print("✅ 批量重命名测试通过")
if __name__ == "__main__":
test_path_parts()
test_path_join()
test_file_ops()
test_dir_ops()
test_batch_rename()
print("\n🎉 第08课全部验证通过!")