Python 文件读写与路径处理
AI 辅助生成本文由 AI 起草并经人工核查,示例均标明软件版本;发现错误请以官方文档为准。
读写文件是脚本最基础的能力。这一篇讲清 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=""。