12 · 文件 I/O 与序列化

12 · 文件 I/O 与序列化

导语:程序要「落地」,就离不开读写文件------把结果存成 CSV 给 Excel 打开,把数据存成 JSON 传给前端,把状态存成 pickle 下次接着用。这一篇讲清 Python 的文件读写、现代路径操作 pathlib,以及 CSV、JSON、pickle 三种序列化方式。

1. open 与 with 语句

读文件用 open(),配合 with 语句自动关闭:

python 复制代码
with open("data.txt", encoding="utf-8") as f:
    content = f.read()
    print(content)

with 会自动关闭文件 (即使中途出错),不用手动 f.close()。这是读写文件的标准姿势。

几种常用模式:

模式 含义 文件不存在时
"r" 只读(默认) 报错
"w" 写入(覆盖) 自动创建
"a" 追加 自动创建
"rb" 二进制读 报错
"wb" 二进制写 自动创建
python 复制代码
# 逐行读取(大文件推荐,省内存)
with open("data.txt", encoding="utf-8") as f:
    for line in f:
        print(line, end="")

# 写入
with open("out.txt", "w", encoding="utf-8") as f:
    f.write("第一行\n")
    f.write("第二行\n")

🚫 避坑 :读写文本 文件务必加 encoding="utf-8"。Windows 上默认编码可能是 GBK,不加会导致中文乱码或报错。"rb"/"wb" 用于图片、音频等二进制 文件,此时不要加 encoding。

2. pathlib:现代路径操作

传统 os.path 用字符串拼路径,容易出错。pathlib 用面向对象的方式操作路径,是现代首选:

python 复制代码
from pathlib import Path

# 当前目录
base = Path(".") / "data"          # 用 / 拼接路径,直观
base.mkdir(exist_ok=True)          # 建目录,已存在不报错

file = base / "report.json"
file.write_text('{"ok": true}', encoding="utf-8")   # 直接写文本
print(file.exists())               # 输出:True
print(file.name)                   # 输出:report.json
print(file.suffix)                 # 输出:.json

# 遍历目录下所有 .txt 文件
for txt in Path(".").glob("*.txt"):
    print(txt)
  • Path / "子目录" 用 / 拼路径,跨平台。
  • read_text / write_text 一行搞定读写。
  • glob() 按模式匹配文件,exists()、name、suffix 都是常用属性。

💡 转行速览 :pathlib 约等于 Java 的 java.nio.file.Path,把路径当对象而非字符串处理。

3. CSV 读写(csv 模块)

CSV 是「逗号分隔值」,Excel 和数据分析最通用的表格格式。用标准库 csv 模块:

python 复制代码
import csv

# 写入 CSV
rows = [
    ["订单号", "金额", "状态"],
    ["A001", "199.0", "已支付"],
    ["A002", "299.0", "待支付"],
]
with open("orders.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

# 读取 CSV
with open("orders.csv", encoding="utf-8") as f:
    reader = csv.DictReader(f)   # 用 DictReader,每行变成字典
    for row in reader:
        print(row["订单号"], row["金额"])
# 输出:
# A001 199.0
# A002 299.0

🚫 避坑 :写 CSV 时 open 要加 newline=""(尤其是 Windows),否则会多出空行。DictReader 用第一行做键,读起来比 reader 的下标更清晰,推荐。

4. JSON 序列化与反序列化

JSON 是互联网数据交换的标准,和 Python 字典几乎一一对应。四个核心函数:

函数 方向 说明
json.dumps(obj) 对象 → 字符串 序列化
json.loads(text) 字符串 → 对象 反序列化
json.dump(obj, f) 对象 → 文件 写文件
json.load(f) 文件 → 对象 读文件
python 复制代码
import json

order = {
    "order_id": "A20260829001",
    "customer": {"name": "赵敏", "city": "杭州"},
    "total": 9797.0,
}

# 序列化成字符串(ensure_ascii=False 让中文不转成 \uXXXX)
text = json.dumps(order, ensure_ascii=False, indent=2)
print(text)
# 输出:
# {
#   "order_id": "A20260829001",
#   "customer": {
#     "name": "赵敏",
#     "city": "杭州"
#   },
#   "total": 9797.0
# }

# 反序列化回字典
data = json.loads(text)
print(data["customer"]["name"])  # 输出:赵敏

# 直接写/读文件
with open("order.json", "w", encoding="utf-8") as f:
    json.dump(order, f, ensure_ascii=False, indent=2)

with open("order.json", encoding="utf-8") as f:
    loaded = json.load(f)
print(loaded["total"])           # 输出:9797.0

💡 提示 :ensure_ascii=False 让中文保持原样、可读;indent=2 让输出带缩进、更美观。但注意 :JSON 里没有「元组」「日期」等类型,json.dumps 遇到它们会报错,需要先转换(如日期转字符串)。

5. pickle 简述

pickle 能把任意 Python 对象序列化成字节流(JSON 只能存基本类型):

python 复制代码
import pickle

config = {"theme": "dark", "sizes": (16, 24), "enabled": True}

# 序列化到文件
with open("config.pkl", "wb") as f:   # 二进制模式
    pickle.dump(config, f)

# 反序列化
with open("config.pkl", "rb") as f:
    loaded = pickle.load(f)
print(loaded["sizes"])  # 输出:(16, 24)  ------ 元组被完整保留

🚫 避坑 :pickle 只能用于自己可控的、可信的数据 。绝不要 pickle.load 来自不可信来源的文件------反序列化可以执行任意代码,是严重的安全风险。跨语言、跨系统交换数据请用 JSON。

6. 实战演练:读取 CSV 汇总成 JSON 报告

需求:读一个订单 CSV 文件,统计总金额、订单数,生成 JSON 报告。

python 复制代码
import csv
import json
from pathlib import Path

def summarize_orders(csv_path: str, report_path: str) -> None:
    """读取订单 CSV,汇总统计并生成 JSON 报告。"""
    orders = []
    with open(csv_path, encoding="utf-8") as f:
        reader = csv.DictReader(f)
        for row in reader:
            orders.append(
                {
                    "order_id": row["订单号"],
                    "amount": float(row["金额"]),
                    "status": row["状态"],
                }
            )

    paid_orders = [o for o in orders if o["status"] == "已支付"]
    report = {
        "total_orders": len(orders),
        "paid_orders": len(paid_orders),
        "total_amount": round(sum(o["amount"] for o in orders), 2),
        "paid_amount": round(sum(o["amount"] for o in paid_orders), 2),
    }

    Path(report_path).write_text(
        json.dumps(report, ensure_ascii=False, indent=2),
        encoding="utf-8",
    )
    print(f"报告已生成:{report_path}")


if __name__ == "__main__":
    summarize_orders("orders.csv", "report.json")

假设 orders.csv 内容:

text 复制代码
订单号,金额,状态
A001,199.0,已支付
A002,299.0,待支付
A003,149.0,已支付

生成的 report.json:

json 复制代码
{
  "total_orders": 3,
  "paid_orders": 2,
  "total_amount": 647.0,
  "paid_amount": 348.0
}

这个「CSV 进、JSON 出」的流程,正是日常数据处理最常见的样子。

7. 常见错误与避坑

  1. 忘写 encoding="utf-8":中文乱码,Windows 上尤其明显。
  2. "w" 覆盖了原文件 :只想追加却用了 "w",数据被清空。追加要用 "a"。
  3. CSV 少了 newline="":Windows 下出现多余空行。
  4. ensure_ascii=True(默认) :中文变 \uXXXX,可读性差,加 ensure_ascii=False。
  5. 对不可信文件用 pickle:安全风险,改用 JSON。

8. 小结

  • with open(...) 自动关文件;文本读写加 encoding="utf-8",二进制用 rb/wb。
  • pathlib 用 / 拼路径、read_text/write_text 读写、glob 匹配,现代首选。
  • csv.DictReader 把每行变字典,最易读。
  • json.dumps/loads/dump/load 四个函数,ensure_ascii=False 保中文,indent 美化。
  • pickle 能存任意对象但只用于可信数据;跨语言交换用 JSON。

9. 练习与思考

  1. 写一个脚本,读取用户输入的文本,追加写入 diary.txt(用 "a" 模式)。
  2. 把一份学生成绩的字典列表 [{"name": "张三", "score": 90}, ...] 写成 CSV 文件。
  3. 用 pathlib 列出当前目录下所有 .py 文件,并打印它们的名字。
  4. 思考:什么场景该用 JSON、什么场景该用 CSV、什么场景该用 pickle?

💡 提示:第 4 题从「是否结构化」「是否需要跨语言」「是否需要存对象」三个角度思考。

10. 延伸阅读


📚 本系列导航

如果觉得有用,欢迎收藏、点赞、转发,让更多人少走弯路。

相关推荐
迅猛龙办公室1 小时前
python实现倒序输出数字
开发语言·python
全栈练习生11 小时前
AI Agent 沙箱
python·ai
SEO_juper12 小时前
用 Python 写一个 GEO 可见性检查脚本:你的网站现在能被 AI 引用吗
开发语言·人工智能·爬虫·python·seo·外贸独立站
用户83562907805113 小时前
使用 Python 对 Excel 工作表进行排序
后端·python
for_ever_love__13 小时前
MySQL 全文索引实战:FULLTEXT、ngram 中文分词与 MATCH AGAINST 到底该怎么用
java·python·mysql·全文检索·分词·索引·ngram
用户83562907805113 小时前
使用 Python 合并 PowerPoint 演示文稿
后端·python
weixin_4617694013 小时前
VS Code 中创建 Jupyter 文件(.ipynb)
ide·python·jupyter
2601_9669496514 小时前
多市场量化策略的数据接口应该如何设计:从数据层架构到策略接入
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
全栈弄潮儿14 小时前
Python实战第1期:Python环境搭建与第一个程序
python
心易行者14 小时前
Agent应用+API端点商业化进阶实战:从单体智能体到可付费调用的API全流程
运维·服务器·人工智能·python·apache