Python 如何正确读写 CSV 文件?csv.reader、DictReader 和 newline 参数要注意什么?
简化版
Python 读写 CSV 推荐使用标准库 csv,不要自己用 split(",") 解析。普通行用 csv.reader / csv.writer,按列名处理用 DictReader / DictWriter;打开文件时通常要指定 encoding,并在写入或读取 CSV 时使用 newline="" 让 csv 模块正确处理换行。
详细版
基础读取:
import csv
with open("users.csv", "r", encoding="utf-8", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row)
按字典读取:
with open("users.csv", "r", encoding="utf-8", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"])
写入 CSV:
with open("users.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["id", "name"])
writer.writerow([1, "Alice"])
常见注意点:
- 不要用字符串
split(",")解析 CSV,因为字段里可能包含逗号、引号和换行; newline=""很重要,尤其在 Windows 上可以避免多余空行等问题;- 中文 CSV 建议显式指定
encoding,和数据来源保持一致; - Excel 场景有时需要
utf-8-sig处理 BOM 兼容问题。
完整版教学
一、CSV 看起来简单,实际有格式规则
CSV 表面上是用逗号分隔:
id,name
1,Alice
2,Bob
但真实 CSV 可以包含更复杂内容:
id,name,remark
1,Alice,"hello, world"
2,Bob,"line1
line2"
如果用:
line.split(",")
第一行 remark 里的逗号会被错误拆开,多行字段也会彻底乱掉。CSV 有引号、转义、换行等规则,所以应该交给 csv 模块处理。
二、reader 和 writer 适合按位置处理
csv.reader 每次返回一行列表:
import csv
with open("users.csv", "r", encoding="utf-8", newline="") as f:
reader = csv.reader(f)
header = next(reader)
for row in reader:
user_id = row[0]
name = row[1]
print(user_id, name)
这种方式适合列很少、位置固定、处理逻辑简单的场景。
写入时:
with open("users.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
writer.writerow(["id", "name"])
writer.writerows([
[1, "Alice"],
[2, "Bob"],
])
csv.writer 会自动处理必要的引号和转义,不需要自己拼接字符串。
三、DictReader 和 DictWriter 适合按列名处理
当 CSV 有表头时,DictReader 更可读:
with open("users.csv", "r", encoding="utf-8", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["id"], row["name"])
写入字典:
fields = ["id", "name"]
with open("users.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
writer.writerow({"id": 1, "name": "Alice"})
它的好处是列顺序变化时更不容易写错,代码语义也清楚。缺点是比列表方式稍微多一点开销,不过大多数业务场景完全可以接受。
四、newline 参数为什么经常被问
官方文档建议用 newline="" 打开 CSV 文件。原因是文本文件对象本身可能处理换行,而 CSV 模块也要处理换行。如果两层都插手,可能出现额外空行或解析异常。
典型写法是:
open("data.csv", "w", encoding="utf-8", newline="")
这不是玄学,而是把 CSV 格式内的换行规则交给 csv 模块统一管理。
五、编码和 Excel 兼容问题
如果 CSV 面向程序之间交换,通常用 UTF-8:
encoding="utf-8"
如果要给某些版本的 Excel 直接打开,中文乱码时可能需要:
encoding="utf-8-sig"
utf-8-sig 会处理 UTF-8 BOM。它不是 CSV 标准本身的问题,而是某些工具识别编码的习惯问题。面试时可以提到,但不要把它当成所有 CSV 的默认选择。
六、常见误区与追问
易错点:CSV 不是“按逗号 split”。引号、逗号、换行、转义、编码和 Excel 兼容都会让手写解析很快失控。
- 误区:CSV 行可以直接用
line.split(",")解析。 字段里可能包含逗号、双引号或换行,例如"Tom, Jr."是一个字段,手写 split 会把它拆坏。 - 追问:为什么打开 CSV 常写
newline=""? 让csv模块自己处理换行规则,避免文本层自动换行转换和 csv 写入换行叠加,尤其在 Windows 上可能出现空行。 - 误区:
reader和DictReader只是写法偏好。reader按位置取字段,适合列顺序稳定的简单数据;DictReader按列名取字段,更适合可读性和列顺序变化。 - 追问:Excel 打开中文 CSV 乱码怎么处理? 常见做法是使用
utf-8-sig写入带 BOM 的 UTF-8 文件,让部分 Excel 版本更容易识别编码。 - 误区:CSV 能可靠表达复杂嵌套结构。 CSV 更适合二维表;嵌套对象、数组、层级配置更适合 JSON、Parquet 或数据库表设计。
- 追问:写 CSV 时为什么要显式 fieldnames?
DictWriter需要知道列顺序和允许的列集合,显式 fieldnames 可以稳定输出结构,也能暴露多余字段或缺失字段问题。
七、加强记忆
CSV 不是简单的逗号切割,而是一种有引号、转义和换行规则的文本格式。读写用 csv.reader、csv.writer,有表头时用 DictReader、DictWriter;打开文件显式指定编码,并记住 newline="",让 CSV 模块自己处理格式内的换行。