Python 文件读写与路径处理

AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。

Python 3.13

读写文件是脚本最基础的能力。这一篇讲清 with、pathlib、JSON 与 CSV,以及编码问题怎么避免。

环境准备

示例在 Python 3.13 下验证,无需额外依赖(JSON / CSV 都在标准库里)。

python -c "import sys; print(sys.version)"
# 3.13.x

用 with 打开文件

with 会在代码块结束时自动关闭文件,即使中途抛异常:

with open("notes.txt", "r", encoding="utf-8") as f:
    content = f.read()

不写 with 就得自己管 f.close(),容易漏。

常用模式:

模式 含义 文件不存在时
"r" 读(默认) 抛 FileNotFoundError
"w" 写,先清空 新建
"a" 追加写 新建
"x" 独占新建 已存在则抛 FileExistsError
"rb" / "wb" 二进制读 / 写 同 r / w

读文本的三种方式

with open("notes.txt", encoding="utf-8") as f:
    print(f.read())        # 一次读完,适合小文件
with open("notes.txt", encoding="utf-8") as f:
    for line in f:         # 逐行迭代,适合大文件(内存友好)
        print(line.rstrip("\n"))
with open("notes.txt", encoding="utf-8") as f:
    lines = f.read().splitlines()   # 得到去掉换行符的列表

推荐第二种:一行一行处理,几百 MB 的日志也不会爆内存。

写文件:

with open("out.txt", "w", encoding="utf-8") as f:
    f.write("第一行\n")
    f.writelines(["第二行\n", "第三行\n"])   # 注意不会自动加换行

pathlib:路径就该这样写

用字符串拼路径容易出错,标准库 pathlib 更安全:

from pathlib import Path

p = Path("data") / "2026" / "notes.txt"
p.parent        # Path('data/2026')
p.name          # 'notes.txt'
p.stem          # 'notes'
p.suffix        # '.txt'
p.exists()      # False

常用操作:

Path("data/reports").mkdir(parents=True, exist_ok=True)   # 递归建目录,已存在不报错

Path("notes.txt").write_text("内容", encoding="utf-8")
Path("notes.txt").read_text(encoding="utf-8")

for file in Path("data").glob("**/*.csv"):   # 递归匹配
    print(file)

Path.home()      # 用户目录
Path.cwd()       # 当前工作目录
Path(__file__).resolve().parent   # 脚本所在目录(比相对路径可靠)

Path 对象可以直接传给 open,也可以直接用它自己的方法,不必再 open。

JSON

配置与接口数据的默认格式:

import json

data = {"name": "小明", "tags": ["python", "web"], "vip": False}

with open("config.json", "w", encoding="utf-8") as f:
    json.dump(data, f, ensure_ascii=False, indent=2)

with open("config.json", encoding="utf-8") as f:
    loaded = json.load(f)
  • ensure_ascii=False:让中文正常显示,否则写成 \u4e2d\u6587。
  • indent=2:缩进,方便人读与 diff。
  • 字符串与对象的互转用 json.dumps() / json.loads()。

类型对应关系:dict → object、list → array、str → string、int/float → number、True/False → true/false、None → null。反过来读回来时 null 变成 None。

CSV

import csv

# 写:newline="" 必须写,否则 Windows 下会多出空行
with open("users.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["id", "name"])
    writer.writerow([1, "小明"])

按列名读更省心:

with open("users.csv", encoding="utf-8", newline="") as f:
    for row in csv.DictReader(f):
        print(row["name"])     # row 是 dict,键来自表头

写字典行:

with open("users.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["id", "name"])
    writer.writeheader()
    writer.writerow({"id": 1, "name": "小明"})

常见错误与注意事项

1. 不写 encoding

Windows 默认编码可能是 GBK,读 UTF-8 文件会 UnicodeDecodeError。读写文本永远显式写 encoding="utf-8"。

2. 写 CSV 忘了 newline=""

在 Windows 上每行之间会出现空行。这是 csv 模块文档明确要求的参数。

3. 用相对路径,换个目录就找不到文件

脚本里的相对路径依赖「当前工作目录」,不是脚本所在目录。用:

BASE = Path(__file__).resolve().parent
config = BASE / "config.json"

4. 用 w 模式打开想追加的文件

"w" 会先清空。追加请用 "a"。

5. 忘记关闭文件句柄

循环里 open 却不关,可能触发「too many open files」。用 with 就不会有这个问题。

6. 直接 json.dump 自定义对象

json 只认内置类型,遇到自定义类会 TypeError。要么转成 dict,要么用 default= 指定转换函数:

json.dump(user, f, default=lambda o: o.__dict__, ensure_ascii=False)

小结

  • 读写文件一律用 with,显式写 encoding="utf-8"。
  • 大文件逐行迭代,不要一次 read()。
  • 路径用 pathlib,脚本内路径基于 Path(__file__)。
  • JSON 用 ensure_ascii=False + indent=2;CSV 写时加 newline=""。

下一步