>>>PyPathPython 学习站
首页›核心篇›kp-016
核心篇 · Core lv.2 核心 kp-016

文件与 IO(pathlib)

前置知识:kp-008、kp-015

1. 一句话定义

open() 返回文件对象(迭代器),配合 with 自动关闭;路径操作用 pathlib.Path(现代首选),文本进出必须显式管理编码;结构化数据交给 json/csv 标准库。

2. 为什么重要

读文件、写报告、处理日志是所有方向共用的地基能力。编码坑(Windows GBK vs UTF-8)与"忘关文件"是真实世界最常见的两类事故。

3. 前置知识

kp-008(str 与 bytes)、kp-015(异常)。

4. 核心概念

  • open 四件套:模式(r/w/a/x + b)、编码(文本模式始终显式 encoding="utf-8")、with(自动 close)、文件可迭代(逐行惰性,kp-013 管道友好)。
  • pathlib.Path:面向对象的路径——Path("data") / "file.csv",read_text/write_text/read_bytes,glob/iterdir/exists/mkdir。
  • JSON:json.load/loads(入)、json.dump/dumps(出),ensure_ascii=False 保留中文。

5. 原理与机制

python
from pathlib import Path
import json, csv

# 读文本:with + 显式编码
p = Path("notes.txt")
text = p.read_text(encoding="utf-8")            # 小文件一步到位

# 大文件逐行流式(不整读进内存)
with open(p, encoding="utf-8") as f:
    for line in f:
        process(line)

# 写 JSON
data = {"name": "蛇", "scores": [90, 80]}
Path("out.json").write_text(
    json.dumps(data, ensure_ascii=False, indent=2),
    encoding="utf-8",
)

# 逐行读 CSV(含表头)
with open("scores.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        print(row["name"], row["score"])

6. 关键事实(模型/图示)

text
打开模式:r 读(默认)  w 覆盖写(清空!)  a 追加  x 新建(存在即报错)
         + 读改  b 二进制(此时 encoding 参数无意义)
文本模式进出 = bytes ⇄ str 的 encode/decode 自动发生(kp-008)

w 会立即清空已有文件——写文件前想清楚模式。

7. 直观类比

文件对象像水龙头:with 是"用完关紧"的责任条款;encoding 是水质标准——不声明,水管(不同操作系统默认)可能给你不同水质,于是"在我电脑上是好的"。

8. 实例与案例

python
# 批量处理目录下所有 txt
for p in Path("docs").glob("*.txt"):
    words = len(p.read_text(encoding="utf-8").split())
    print(p.name, words)

# 原子写(先写临时文件再替换,避免写一半崩溃损坏)
tmp = p.with_suffix(".tmp")
tmp.write_text(content, encoding="utf-8")
tmp.replace(p)

9. 常见误区

  1. 不写 encoding —— Windows 默认 GBK、Linux 默认 UTF-8,跨平台必然翻车;文本模式永远显式 encoding="utf-8"。
  2. 忘 with —— 手动 close 且中途抛异常就泄漏;一律 with。
  3. 用 open() 读 pickle 信任外部数据 —— pickle 反序列化可执行任意代码(安全,见 kp-048);跨信任边界用 JSON。
  4. 路径拼接用字符串 + —— 分隔符硬编码;用 pathlib 的 / 运算符。

10. 自测题

  1. open("f.txt", "w") 对已存在文件做了什么?
  2. 为什么读大文件推荐逐行迭代而不是 read()?
  3. json.dumps(..., ensure_ascii=False) 的意义?
参考答案
  1. 立即截断清空内容,从头开始写。
  2. read() 把整个文件载入内存;逐行迭代是惰性流,内存占用与文件大小无关。
  3. 非 ASCII 字符直接输出原文而非 \uXXXX 转义,文件可读、体积更小(注意仍要 utf-8 编码写盘)。

11. 与其他知识点的关系

  • kp-025 上下文管理器:with 的机制层。
  • kp-013 生成器:文件对象即迭代器,管道天然成立。
  • kp-048 安全与伦理:pickle 与路径注入风险。

12. 延伸阅读

  • pathlib 官方文档:https://docs.python.org/zh-cn/3/library/pathlib.html