【Python】基础语法入门(二十四)——文件与目录操作进阶:安全、高效地处理本地数据


📁 说明 :文件和目录操作是绝大多数 Python 应用的基础功能------无论是读取配置、保存日志,还是批量处理数据。本篇深入讲解 pathlib、os、shutil、glob 等模块的高级用法 ,并强调安全性、健壮性与跨平台兼容性,助你写出专业级的文件处理代码。

你将掌握:

  • 用 pathlib 实现现代、面向对象的路径操作
  • 安全创建/删除目录(避免 FileExistsError 和空目录残留)
  • 高效遍历大型目录(使用生成器避免内存爆炸)
  • 批量重命名、移动、复制文件
  • 处理权限、元数据与临时文件
  • 防范路径遍历等安全风险

1. 为什么推荐 pathlib?(vs os.path)

特性 os.path pathlib.Path
风格 函数式(os.path.join("a", "b")) 面向对象(Path("a") / "b")
可读性 较低 高(支持运算符)
跨平台 需注意分隔符 自动处理
方法丰富度 基础 内置 .read_text(), .mkdir() 等

✅ 从 Python 3.4 起,官方推荐使用 pathlib


2. 核心操作实战

2.1 创建目录(安全且递归)

python 复制代码
from pathlib import Path

# 创建单层目录(存在则报错)
Path("logs").mkdir(exist_ok=True)

# 创建多层目录(如 a/b/c)
Path("data/raw/images").mkdir(parents=True, exist_ok=True)

🔑 参数说明:

  • parents=True:自动创建父目录
  • exist_ok=True:目录已存在时不报错

2.2 安全写入文件(避免覆盖/损坏)

方法1:原子写入(推荐)
python 复制代码
from pathlib import Path
import tempfile

def safe_write(file_path: Path, content: str):
    """先写临时文件,再原子替换原文件"""
    with tempfile.NamedTemporaryFile(
        dir=file_path.parent,
        delete=False,
        mode="w",
        encoding="utf-8"
    ) as tmp:
        tmp.write(content)
        tmp_path = Path(tmp.name)
    
    # 原子替换(POSIX 系统保证)
    tmp_path.replace(file_path)

✅ 优势:

  • 写入失败不破坏原文件
  • 避免程序崩溃导致半写入文件
方法2:简单覆盖(适合非关键数据)
python 复制代码
Path("config.json").write_text('{"debug": true}', encoding="utf-8")

2.3 遍历目录(高效 & 可控)

场景1:仅当前目录下的文件
python 复制代码
for item in Path("docs").iterdir():
    if item.is_file():
        print(item.name)
场景2:递归遍历所有 .txt 文件
python 复制代码
# 使用 glob(简洁)
for txt_file in Path("project").rglob("*.txt"):
    print(txt_file)

# 使用 walk(更灵活)
for root, dirs, files in Path("data").walk():  # Python 3.12+
    for f in files:
        if f.endswith(".log"):
            print(root / f)

⚠️ 注意:

  • rglob() 返回生成器,内存友好
  • 旧版本 Python(❤️.12)用 os.walk() + Path

2.4 批量操作:重命名、移动、删除

示例:为图片添加前缀
python 复制代码
from pathlib import Path

img_dir = Path("photos")
for i, img in enumerate(img_dir.glob("*.jpg"), start=1):
    new_name = f"vacation_{i:03d}.jpg"
    img.rename(img_dir / new_name)
移动文件到归档目录
python 复制代码
archive = Path("archive")
archive.mkdir(exist_ok=True)

for log in Path("logs").glob("*.log"):
    log.replace(archive / log.name)  # 移动(同盘)或复制+删除(跨盘)
安全删除目录(非空)
python 复制代码
import shutil

# 删除整个目录树
shutil.rmtree("temp_data", ignore_errors=True)

# 或用 pathlib(Python 3.12+)
Path("temp_data").rmtree(ignore_errors=True)

❌ 不要用 os.rmdir():只能删空目录


3. 获取文件元数据

python 复制代码
from pathlib import Path
import datetime

p = Path("report.pdf")

if p.exists():
    stat = p.stat()
    print(f"大小: {stat.st_size} 字节")
    mtime = datetime.datetime.fromtimestamp(stat.st_mtime)
    print(f"修改时间: {mtime}")
    
    # 检查权限(Unix-like 系统)
    print(f"可读: {os.access(p, os.R_OK)}")

💡 提示:

  • st_mtime = 修改时间
  • st_ctime = 创建时间(Windows)/ 状态变更时间(Unix)

4. 安全性:防范路径遍历攻击

当处理用户输入的文件名时,必须校验路径合法性!

危险示例(切勿模仿!)

python 复制代码
# 用户输入 filename = "../../../etc/passwd"
filename = input("输入文件名: ")
Path("uploads") / filename  # 可能逃出 uploads 目录!

安全做法:限制在指定目录内

python 复制代码
def safe_join(base_dir: Path, user_path: str) -> Path:
    """确保 user_path 不会逃出 base_dir"""
    resolved = (base_dir / user_path).resolve()
    if not resolved.is_relative_to(base_dir.resolve()):
        raise ValueError("非法路径!")
    return resolved

# 使用
try:
    safe_path = safe_join(Path("uploads"), "../../secret.txt")
except ValueError as e:
    print(e)  # 非法路径!

🔒 关键函数:

  • Path.resolve():解析绝对路径(含 ..)
  • Path.is_relative_to():检查是否在指定目录下(Python 3.9+)

5. 临时文件与目录(回顾 + 进阶)

自动清理的临时工作区

python 复制代码
import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp_dir:
    work_path = Path(tmp_dir)
    
    # 在此目录下进行复杂操作
    (work_path / "input.csv").write_text("...")
    process_data(work_path)
    
    # 退出 with 块后自动删除整个目录

✅ 适用场景:

  • 解压 ZIP 后处理文件
  • 生成中间报告
  • 测试隔离环境

6. 常见陷阱与解决方案

问题 原因 解决方案
FileNotFoundError 父目录不存在 用 mkdir(parents=True)
中文文件名乱码 编码未指定 open(..., encoding="utf-8")
权限拒绝 无写权限 检查 os.access() 或捕获 PermissionError
跨平台路径错误 硬编码 \ 或 / 始终用 Path 或 os.path.join
删除非空目录失败 用了 os.rmdir 用 shutil.rmtree

7. 实战:构建一个"日志归档工具"

整合所学知识,编写一个实用小工具:

python 复制代码
#!/usr/bin/env python3
from pathlib import Path
import shutil
from datetime import datetime

def archive_logs(log_dir: Path, archive_dir: Path):
    """将 7 天前的日志移至归档目录"""
    archive_dir.mkdir(parents=True, exist_ok=True)
    
    now = datetime.now()
    for log_file in log_dir.glob("app_*.log"):
        stat = log_file.stat()
        mtime = datetime.fromtimestamp(stat.st_mtime)
        days_old = (now - mtime).days
        
        if days_old >= 7:
            # 构建带日期的归档名
            date_str = mtime.strftime("%Y%m%d")
            stem = log_file.stem
            ext = log_file.suffix
            new_name = f"{stem}_{date_str}{ext}"
            
            target = archive_dir / new_name
            log_file.replace(target)
            print(f"归档: {log_file.name} → {new_name}")

if __name__ == "__main__":
    archive_logs(Path("logs"), Path("logs/archive"))

✨ 功能亮点:

  • 自动创建归档目录
  • 按修改时间判断是否过期
  • 重命名包含日期,避免冲突

8. 总结:文件操作黄金法则

  1. 用 pathlib.Path 代替字符串拼接路径
  2. 写入关键文件时使用原子操作
  3. 遍历大目录用生成器(glob, iterdir)
  4. 处理用户输入路径时严格校验
  5. 删除目录用 shutil.rmtree
  6. 始终指定文本编码(utf-8)

🐍 记住 :

"文件系统是不可靠的外部世界,你的代码必须做好防御。"

------ 专业开发者的基本素养


下一步练习

  1. 为你的 To-Do List 添加"自动备份"功能 (每天备份 tasks.json 到 backup/)
  2. 编写一个"清理下载文件夹"脚本(按扩展名分类移动文件)
  3. 实现一个安全的文件上传接口(校验路径、限制大小、扫描内容)

🧹 掌控文件系统,就是掌控数据的命脉。

用稳健的代码,守护你的每一份数据!

继续精进,成为文件操作的 Python 高手!

相关推荐
sell-cloud6 分钟前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
不会就选b10 分钟前
C++补充部分(一)--lambda 表达式
开发语言·c++
Navicat中国2 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI2 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区2 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
Pniubi3 小时前
HashMap的扩容和树化边界
java·开发语言
XCDoris4 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy4 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V4 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI4 小时前
AI英语教培智能体的开发
人工智能