Python 文件读写与数据持久化实战

Daoman Python AI 的后端开发或模型训练中,我们经常需要处理数据的持久化(Persistence)。所谓持久化,是指将数据从易失的存储介质(通常是内存)转移到可以长久保存的介质(通常是硬盘、SSD)中。实现这一目标最直接、最标准的方式,就是通过文件系统将数据保存到文件里。


1. 理解文件系统的抽象层

计算机的文件系统是一套成熟的“数据管家”方案。它用“文件”“树形目录”的简单逻辑概念,彻底屏蔽了硬盘磁道寻址、SSD 磨损平衡、USB 协议交互这些复杂的底层物理细节。

作为应用层开发者,你完全不需要提前找硬盘的空白物理扇区,也不用操心断电后的数据校验问题——文件系统会自动分配空间、管理索引、处理故障容错。你只需要通过绝对路径/相对路径 + 文件名,就能轻松完成“存东西、取东西”的操作,这极大降低了存储开发的入门门槛。


2. 打开与关闭文件:open() 函数核心解析

Python 中操作文件的官方推荐入口是内置函数 open()。通过传入不同的操作模式字符串,你可以控制文件的读写权限、处理方式(文本/二进制)、更新权限等。

2.1 常用操作模式速查

下表整理了高频场景下的模式组合,避免记混单字符的含义:

操作模式组合核心权限关键细节高频场景
'r'/'rt'只读文本默认模式;文件不存在直接报错读取配置、训练数据预览
'w'/'wt'覆盖写文本文件不存在则创建;存在则清空所有内容重写临时生成新的配置/日志备份
'a'/'at'追加写文本文件不存在则创建;存在则在末尾追加,光标默认在末尾爬虫数据入库、训练实时日志
'x'/'xt'排他写文本文件不存在则创建;存在则直接报错防止多人/多进程误覆盖关键文件
'rb'只读二进制直接读原始字节流;无需编码参数读取图片、模型权重(.pth/.pt)、压缩包
'wb'覆盖写二进制直接写原始字节流保存图片、模型、二进制日志
'r+'/'w+'更新文本同时支持读写;w+ 会先清空旧文件需同时读取和修改的简单配置

🚩 新手避坑指南(必看)
处理中文文本、JSON/YAML 等结构化文本文件时,务必显式指定 encoding='utf-8'
不要依赖操作系统的默认编码(比如 Windows 下的 GBK、Mac/Linux 早期可能用的 Latin-1),否则 90% 以上的概率会遇到经典的 UnicodeDecodeErrorUnicodeEncodeError


3. 文本读写的工业级实践

虽然 Python 提供了 file.close() 手动关闭文件的方法,但在生产环境或团队协作代码中,100% 推荐使用 with 关键字(上下文管理器)

它有两个不可替代的优势:

  1. 自动安全释放资源:即使读写过程中发生了 ValueErrorIOError 甚至是系统级异常,文件句柄也会被立刻释放,不会造成资源泄漏(资源泄漏在高并发服务中会导致“Too many open files”报错,直接挂服务)。
  2. 代码可读性更强:缩进块明确了“文件操作的有效范围”,团队成员一眼就能看懂哪里在操作文件。

3.1 读取文本文件的三种主流方式

根据文件大小和业务需求,选择最适合的读取方案,不要盲目用全量读取

# 所有示例都统一使用 with 上下文管理器 + utf-8 编码
with open('致橡树.txt', 'r', encoding='utf-8') as file:
    # ========== 方式 A:逐行迭代(⭐️⭐️⭐️ 工业级首选) ==========
    # 每次只加载一行到内存,内存占用永远是 O(1)
    # 适合处理 GB 级的日志、千万条的爬虫数据
    print("=== 逐行迭代(strip去除换行/空格) ===")
    for line in file:
        # 记得用 strip() 或 rstrip('\n') 去掉自动带的换行符
        print(line.strip())

    # ========== 方式 B:全量读取(适合 <10MB 的文件) ==========
    # 一次性加载所有内容到内存,得到一个完整的字符串
    # 注意:上面的 for 循环已经把文件指针移到末尾了,需要重置
    file.seek(0)  # 把文件指针移回文件开头
    print("\n=== 全量读取 ===")
    full_content = file.read()
    print(full_content[:100])  # 只打印前100个字符演示

    # ========== 方式 C:列表读取(适合需要索引某一行的场景) ==========
    # 把每行作为一个元素存入列表,内存占用和全量读取差不多
    file.seek(0)
    print("\n=== 列表读取(打印第3行) ===")
    lines_list = file.readlines()
    if len(lines_list) >= 3:
        print(lines_list[2].strip())

三种方式的对比总结:

  • 逐行迭代(方式 A):内存占用极低,适合超大文件,能应对生产级日志流。
  • 全量读取(方式 B):简单直接,适合小文件一次性处理,例如加载 JSON 配置。
  • 列表读取(方式 C):方便按索引访问某一行,但会占用较多内存,慎用于大文件。

3.2 写入与追加数据

根据是否保留旧内容,选择 'w'(覆盖)或 'a'(追加)模式:

# ========== 场景 1:覆盖写(新建或清空) ==========
with open('致橡树-精简版.txt', 'w', encoding='utf-8') as file:
    # write() 不会自动加换行符,需要手动加 \n
    file.write("我如果爱你——\n")
    file.write("绝不像攀援的凌霄花,\n")
    file.write("借你的高枝炫耀自己;")

# ========== 场景 2:追加写(保留旧内容,末尾加新的) ==========
with open('致橡树.txt', 'a', encoding='utf-8') as file:
    # 追加两行赏析内容
    file.write("\n\n--- 诗歌赏析 ---")
    file.write("\n《致橡树》通过木棉与橡树的对话,展现了独立、平等、相互扶持的现代爱情观。")

写入小贴士

  • 覆盖写 'w' 会一键清空原有数据,操作前请确认备份。
  • 追加写 'a' 的光标自动定位到文件末尾,无需手动 seek
  • 如果需要在末尾换行再加入新内容,记得在新内容前手动添加 \n

通过本文的梳理,你应该已经掌握了 Python 文件读写的核心技能和工业级最佳实践。无论是处理配置、日志,还是训练数据、模型权重,善用 open()with 和合适的读写模式,可以让你的数据持久化代码既高效又稳健。