跳转至

01 - 文件与路径操作

学习时间: 1.5小时 重要性: ⭐⭐⭐⭐⭐ 每个项目都会用到


🎯 学习目标

  • 掌握 pathlib 的核心用法
  • 了解 osshutil 的常用功能
  • 能处理文件和目录的各种操作

📂 pathlib - 现代化的路径操作

基本概念

Python
from pathlib import Path

# 创建路径对象
path = Path("data/example.txt")  # Path()提供面向对象的文件路径操作

# 路径拼接(使用 / 运算符)
path = Path("data") / "subdir" / "file.txt"
# 等价于
path = Path("data").joinpath("subdir", "file.txt")

# 获取当前目录和家目录
cwd = Path.cwd()       # 当前工作目录
home = Path.home()     # 用户主目录

路径信息

Python
path = Path("data/projects/example.py")

# 基本信息
print(path.name)         # "example.py" - 文件名(含扩展名)
print(path.stem)         # "example" - 文件名(不含扩展名)
print(path.suffix)       # ".py" - 扩展名
print(path.parent)       # "data/projects" - 父目录
print(path.parents[0])   # "data/projects"
print(path.parents[1])   # "data"
print(path.root)         # "\" (Windows) 或 "/" (Unix)

# 存在性检查
print(path.exists())     # True/False - 是否存在
print(path.is_file())    # True/False - 是否是文件
print(path.is_dir())     # True/False - 是否是目录

# 绝对路径和相对路径
print(path.absolute())   # 获取绝对路径
print(path.resolve())    # 解析符号链接,获取绝对路径

文件读写

Python
from pathlib import Path

# 写入文件
Path("output.txt").write_text("Hello, World!", encoding="utf-8")

# 读取文件
content = Path("output.txt").read_text(encoding="utf-8")

# 二进制读写
Path("image.jpg").write_bytes(image_data)
data = Path("image.jpg").read_bytes()

# 实用示例:保存配置
config = {
    "name": "MyApp",
    "version": "1.0",
    "debug": True
}

import json
config_path = Path("config.json")
config_path.write_text(json.dumps(config, ensure_ascii=False, indent=2))

目录操作

Python
from pathlib import Path

# 创建目录
Path("data/subdir").mkdir(parents=True, exist_ok=True)
# parents=True: 创建父目录(如果不存在)
# exist_ok=True: 目录已存在不报错

# 遍历目录
path = Path("data")
for item in path.iterdir():
    print(f"{'目录' if item.is_dir() else '文件':<4} {item.name}")

# 递归遍历(查找所有Python文件)
for py_file in Path(".").rglob("*.py"):
    print(py_file)

# 非递归遍历(只查找当前目录)
for txt_file in Path(".").glob("*.txt"):
    print(txt_file)

# 统计目录中的文件数
py_count = len(list(Path("project").rglob("*.py")))
print(f"项目中有 {py_count} 个Python文件")

文件操作

Python
from pathlib import Path

# 复制、移动、重命名
Path("source.txt").rename("new_name.txt")      # 重命名/移动
Path("source.txt").replace("destination.txt")  # 移动(覆盖)

# 创建空文件
Path("new_file.txt").touch()

# 删除
Path("temp.txt").unlink()         # 删除文件
Path("temp_dir").rmdir()          # 删除空目录

# 检查文件权限
print(Path("file.txt").stat())    # 获取文件状态信息
print(Path("file.txt").stat().st_size)  # 文件大小(字节)
print(Path("file.txt").stat().st_mtime)  # 修改时间(时间戳)

# 实用示例:清理临时文件
def clean_temp_files(directory, pattern="*.tmp"):
    """删除目录下所有匹配pattern的临时文件"""
    path = Path(directory)
    for temp_file in path.glob(pattern):
        temp_file.unlink()
        print(f"已删除: {temp_file}")

clean_temp_files("./temp")

🔧 shutil - 高级文件操作

Python
import shutil
from pathlib import Path

# 复制文件
shutil.copy("source.txt", "destination.txt")      # 复制文件(保留权限)
shutil.copy2("source.txt", "destination.txt")     # 复制文件(保留元数据)

# 复制目录
shutil.copytree("source_dir", "dest_dir")         # 递归复制目录

# 移动文件/目录
shutil.move("old.txt", "new.txt")                # 移动/重命名
shutil.move("old_dir", "new_dir")

# 删除目录(及其内容)
shutil.rmtree("temp_dir")                        # 递归删除

# 获取磁盘使用情况
usage = shutil.disk_usage(".")
print(f"总空间: {usage.total / (1024**3):.2f} GB")
print(f"已使用: {usage.used / (1024**3):.2f} GB")
print(f"可用: {usage.free / (1024**3):.2f} GB")

# 压缩和解压
shutil.make_archive("backup", "zip", "data")     # 压缩目录
shutil.unpack_archive("backup.zip", "extract")   # 解压文件

🗂️ os - 传统路径操作(了解即可)

Python
import os

# 路径拼接(传统方式)
path = os.path.join("data", "subdir", "file.txt")

# 路径信息
print(os.path.dirname(path))    # "data/subdir"
print(os.path.basename(path))   # "file.txt"
print(os.path.splitext(path))   # ("data/subdir/file", ".txt")

# 当前目录和父目录
print(os.getcwd())              # 当前工作目录
os.chdir("/path/to/dir")        # 改变工作目录

# 列出目录内容
print(os.listdir("."))          # 列出当前目录

# 检查路径
print(os.path.exists(path))     # 是否存在
print(os.path.isfile(path))     # 是否是文件
print(os.path.isdir(path))      # 是否是目录

# 环境变量
print(os.environ["PATH"])       # 获取环境变量
os.environ["API_KEY"] = "xxx"   # 设置环境变量

# ⚠️ 注意:新代码优先使用pathlib,更简洁、更安全

💡 实用场景

场景1: 批量重命名文件

Python
from pathlib import Path

def batch_rename(directory, pattern, replacement):
    """
    批量重命名文件

    例如: batch_rename("photos/", "IMG_", "Photo_")
    将 IMG_001.jpg -> Photo_001.jpg
    """
    path = Path(directory)
    count = 0

    for file in path.glob(f"*{pattern}*"):
        new_name = file.name.replace(pattern, replacement)
        new_path = file.parent / new_name

        if not new_path.exists():
            file.rename(new_path)
            count += 1
            print(f"重命名: {file.name} -> {new_name}")

    print(f"共重命名 {count} 个文件")

# 使用
batch_rename("photos/", "IMG_", "Photo_")

场景2: 按扩展名整理文件

Python
from pathlib import Path
from collections import defaultdict

def organize_files(directory):
    """按文件扩展名整理文件到子目录"""
    path = Path(directory)
    files_by_ext = defaultdict(list)

    # 分类文件
    for file in path.iterdir():
        if file.is_file():
            ext = file.suffix[1:] if file.suffix else "no_extension"
            files_by_ext[ext].append(file)

    # 移动文件到对应的子目录
    for ext, files in files_by_ext.items():
        # 创建子目录
        ext_dir = path / ext
        ext_dir.mkdir(exist_ok=True)

        # 移动文件
        for file in files:
            new_path = ext_dir / file.name
            if not new_path.exists():
                file.rename(new_path)
                print(f"移动: {file.name} -> {ext}/{file.name}")

# 使用
organize_files("./downloads")

场景3: 查找并处理大文件

Python
from pathlib import Path

def find_large_files(directory, size_mb=10):
    """查找大于指定大小的文件"""
    path = Path(directory)
    size_bytes = size_mb * 1024 * 1024

    large_files = []

    for file in path.rglob("*"):
        if file.is_file():
            size = file.stat().st_size
            if size > size_bytes:
                large_files.append((file, size))

    # 按大小排序
    large_files.sort(key=lambda x: x[1], reverse=True)  # lambda定义匿名函数,这里用作排序键

    # 打印结果
    for file, size in large_files:
        print(f"{file}: {size / (1024**2):.2f} MB")

    return large_files

# 使用
find_large_files(".", size_mb=5)

场景4: 备份重要文件

Python
from pathlib import Path
import shutil
from datetime import datetime

def backup_files(source_dir, backup_dir, pattern="*.py"):
    """备份匹配pattern的文件"""
    source = Path(source_dir)
    backup = Path(backup_dir)

    # 创建带时间戳的备份目录
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    backup_path = backup / f"backup_{timestamp}"
    backup_path.mkdir(parents=True, exist_ok=True)

    # 复制文件
    count = 0
    for file in source.rglob(pattern):
        # 保持目录结构
        relative_path = file.relative_to(source)
        dest_file = backup_path / relative_path
        dest_file.parent.mkdir(parents=True, exist_ok=True)

        shutil.copy2(file, dest_file)
        count += 1

    print(f"备份完成:{count} 个文件 -> {backup_path}")

# 使用
backup_files("./project", "./backups", "*.py")

场景5: 日志文件清理

Python
from pathlib import Path
from datetime import datetime, timedelta

def clean_old_logs(directory, days=7, pattern="*.log"):
    """删除超过指定天数的日志文件"""
    path = Path(directory)
    cutoff = datetime.now() - timedelta(days=days)
    count = 0

    for log_file in path.glob(pattern):
        # 获取文件修改时间
        mtime = datetime.fromtimestamp(log_file.stat().st_mtime)

        if mtime < cutoff:
            log_file.unlink()
            count += 1
            print(f"删除: {log_file.name} (修改于 {mtime.strftime('%Y-%m-%d')})")

    print(f"清理完成:删除了 {count} 个旧日志")

# 使用
clean_old_logs("./logs", days=7)

📝 练习

练习1: 文件搜索

Python
from pathlib import Path

def search_files(directory, keyword, extension=None):
    """
    在目录中搜索文件名包含keyword的文件

    参数:
        directory: 搜索目录
        keyword: 文件名包含的关键词
        extension: 可选,只搜索特定扩展名(如".py")
    """
    # TODO: 实现这个函数
    pass

# 测试
search_files(".", "test", ".py")

练习2: 空目录清理

Python
def remove_empty_directories(directory):
    """
    递归删除目录下的所有空目录
    提示:从最深的目录开始删除
    """
    # TODO: 实现这个函数
    pass

练习3: 文件同步工具

Python
def sync_directories(source, dest):
    """
    将源目录同步到目标目录
    - 只复制源目录中存在但目标目录中不存在的文件
    - 跳过已存在且大小相同的文件
    """
    # TODO: 实现这个函数
    pass

🎯 自我检查

完成这个主题后,你应该:

  • 优先使用pathlib而不是os
  • 能熟练进行路径操作
  • 能处理文件和目录的增删改查
  • 能解决实际文件处理问题
  • 不查资料完成上面的练习

📚 延伸阅读


下一步: 02 - 数据序列化