专为 config.py 中 ROOT_DIR 等路径配置而写


1. 获取项目根目录(ROOT_DIR)

推荐写法

from pathlib import Path

# 方法1:基于当前文件位置(最常用)
# 假设 config.py 在 scripts/ 目录下
ROOT_DIR = Path(__file__).parent.parent  # 上两级目录

# 方法2:基于工作目录
import os
ROOT_DIR = Path(os.getcwd())

# 方法3:固定路径(不推荐,换电脑会坏)
ROOT_DIR = Path("C:/Users/xxx/project")  # ❌ 别这样

图解 __file__ 的 parent

项目目录/
├── scripts/
│   └── config.py   ← __file__ 在这里
├── watch/
├── extracted/
└── ...

Path(__file__)          = 项目目录/scripts/config.py
Path(__file__).parent   = 项目目录/scripts
Path(__file__).parent.parent = 项目目录  ← ROOT_DIR

2. 构建其他路径

传统字符串方式(麻烦)

import os

# 字符串拼接,要考虑 / 和 \
watch_dir = os.path.join(ROOT_DIR, "watch")
extract_dir = os.path.join(ROOT_DIR, "extracted")

# 还要手动创建目录
os.makedirs(watch_dir, exist_ok=True)

pathlib 方式(简洁)

from pathlib import Path

ROOT_DIR = Path(__file__).parent.parent

# 用 / 直接拼接路径
WATCH_DIR = ROOT_DIR / "watch"
EXTRACT_DIR = ROOT_DIR / "extracted"
COMPRESSED_DIR = ROOT_DIR / "compressed"

# 自动创建目录(包括父目录)
WATCH_DIR.mkdir(parents=True, exist_ok=True)

更多拼接示例

base = Path("/home/user/project")

# 拼接子目录
subdir = base / "data" / "2024"          # /home/user/project/data/2024

# 拼接文件
file = base / "config" / "settings.json"  # /home/user/project/config/settings.json

# 在 config.py 中的实际应用
PATHS = {
    "watch": ROOT_DIR / "watch",
    "extracted": ROOT_DIR / "extracted",
    "compressed": ROOT_DIR / "compressed",
}

3. 常用操作速查表

操作代码结果
获取文件名Path("/a/b/c.txt").namec.txt
获取后缀Path("/a/b/c.txt").suffix.txt
获取纯名Path("/a/b/c.txt").stemc
获取父目录Path("/a/b/c.txt").parent/a/b
改后缀Path("c.txt").with_suffix(".jpg")c.jpg
绝对路径Path("./file").resolve()完整路径
是否存在Path("/a/b").exists()True/False
是文件Path("/a/b").is_file()True/False
是目录Path("/a/b").is_dir()True/False

4. 遍历目录

from pathlib import Path

root = Path("./watch")

# 遍历所有文件和子目录
for item in root.iterdir():
    print(item)  # 可能是文件或目录

# 只遍历文件
for file in root.iterdir():
    if file.is_file():
        print(f"文件: {file.name}")

# 只遍历 .jpg 文件
for jpg in root.glob("*.jpg"):
    print(jpg)

# 递归遍历所有图片(包括子目录)
for img in root.rglob("*.jpg"):  # rglob = recursive glob
    print(img)

5. 实际应用场景

场景1:config.py 中的路径配置

from pathlib import Path

# 项目根目录
PROJECT_ROOT = Path(__file__).parent.parent

# 各种路径
PATHS = {
    "watch": PROJECT_ROOT / "watch",
    "extracted": PROJECT_ROOT / "extracted",
    "compressed": PROJECT_ROOT / "compressed",
    "archived": PROJECT_ROOT / "archived",
    "logs": PROJECT_ROOT / "logs",
}

# 确保目录都存在
for name, path in PATHS.items():
    path.mkdir(parents=True, exist_ok=True)
    print(f"✓ {name}: {path}")

场景2:检查文件类型

from pathlib import Path
from config import ALLOWED_IMAGE_EXTS

def is_allowed_image(file_path: Path) -> bool:
    """检查是否是允许的图片格式"""
    return file_path.suffix.lower() in ALLOWED_IMAGE_EXTS

# 使用
file = Path("photo.JPG")
if is_allowed_image(file):
    print("是合法图片")

场景3:批量重命名

from pathlib import Path

def batch_rename(directory: Path, old_ext: str, new_ext: str):
    """批量修改文件后缀"""
    for file in directory.glob(f"*{old_ext}"):
        new_name = file.with_suffix(new_ext)
        file.rename(new_name)
        print(f"{file.name} -> {new_name.name}")

# 使用
batch_rename(Path("./images"), ".jpeg", ".jpg")

6. 常见错误

错误1:混用字符串和 Path

from pathlib import Path

root = Path("./project")
# 错!不能直接用 +
# path = root + "/subdir"  # ❌ 报错

# 对!用 /
path = root / "subdir"  # ✅

错误2:忘记转换传给旧 API

from pathlib import Path
import os

p = Path("./test.txt")

# 一些旧库只接受字符串
# os.system(f"cat {p}")  # 可能有问题

# 转字符串
os.system(f"cat {str(p)}")  # ✅
# 或
os.system(f"cat {p.as_posix()}")  # ✅ 用正斜杠

错误3:Windows 下的反斜杠

from pathlib import Path

p = Path("C:/Users/name/file.txt")
print(p)           # C:\Users\name\file.txt (Windows 自动转)
print(str(p))      # C:\Users\name\file.txt
print(p.as_posix()) # C:/Users/name/file.txt (正斜杠,用于 URL)

7. 对比:os.path vs pathlib

操作os.path (旧)pathlib (新)
拼接路径os.path.join(a, b)a / b
获取文件名os.path.basename(p)p.name
获取目录os.path.dirname(p)p.parent
获取后缀os.path.splitext(p)[1]p.suffix
绝对路径os.path.abspath(p)p.resolve()
是否存在os.path.exists(p)p.exists()
创建目录os.makedirs(p)p.mkdir(parents=True)

结论:新项目直接用 pathlib,更面向对象、更易读。


8. 给你的 config.py 模板

"""
配置文件
"""
from pathlib import Path

# ==================== 基础路径 ====================
# 项目根目录:config.py 在 scripts/ 下,所以上两级是根目录
PROJECT_ROOT = Path(__file__).parent.parent

# ==================== 各阶段目录 ====================
PATHS = {
    "watch": PROJECT_ROOT / "watch",           # 监听文件夹
    "extracted": PROJECT_ROOT / "extracted",   # 解压目录
    "compressed": PROJECT_ROOT / "compressed", # 压缩后图片
    "archived": PROJECT_ROOT / "archived",     # 最终分卷压缩
    "logs": PROJECT_ROOT / "logs",             # 日志目录
}

# ==================== 辅助函数 ====================
def ensure_dirs():
    """确保所有目录都存在"""
    for path in PATHS.values():
        path.mkdir(parents=True, exist_ok=True)

# 测试
if __name__ == "__main__":
    ensure_dirs()
    for name, path in PATHS.items():
        print(f"{name}: {path}")

参考

  • Python 官方文档:https://docs.python.org/3/library/pathlib.html
  • 建议 Python 版本:3.6+(pathlib 已完善)