Python 内置 csv 模块:核心类与基本读写
处理 CSV 文件,Python 标准库自带的 csv 模块其实就够了。我早年刚入行时,也试过自己写字符串分割逻辑,结果被各种引号、换行符、逗号嵌套搞到崩溃。后来老老实实用内置模块,再没出过解析事故。
说白了,csv 模块提供了四个核心类:reader、writer、DictReader、DictWriter。前两个处理列表形式的数据,后两个处理字典形式的数据。咱们一个一个来看。
reader:逐行读取,返回列表
csv.reader 是最基础的读取方式。它把每一行解析成一个列表,字段按顺序排列。
import csv
with open('recipes.csv', 'r', encoding='utf-8') as f:
reader = csv.reader(f)
for row in reader:
print(row) # 每行是一个列表
输出大概是这样的:
['配方编号', '原料名称', '用量', '单位']
['R001', '面粉', '500', 'g']
['R001', '水', '300', 'ml']
嗯,这里要注意:reader 默认把第一行也当成普通数据。如果你想把第一行当表头,需要手动调用 next() 跳过。
DictReader:按列名读取,返回字典
DictReader 是我个人最常用的类。它自动把第一行作为字段名,后续每行返回一个字典,键就是表头。
import csv
with open('recipes.csv', 'r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
print(row['配方编号'], row['原料名称'], row['用量'])
输出:
R001 面粉 500
R001 水 300
你看,代码可读性一下子高了很多。我在项目中处理配方数据时,几乎清一色用 DictReader。为什么?因为配方表经常有几十个字段,用列表下标去取数据,写起来累,读起来更累。
"配方编号 "(后面多了个空格),DictReader 会把空格也当成键的一部分。后来我养成了习惯,读取前先检查表头,或者用 strip() 清洗一下。
writer:逐行写入,接收列表
写 CSV 文件时,csv.writer 是最直接的方式。它接收列表,一行一行地写进去。
import csv
with open('output.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.writer(f)
writer.writerow(['配方编号', '原料名称', '用量', '单位'])
writer.writerow(['R002', '糖', '200', 'g'])
writer.writerow(['R002', '鸡蛋', '3', '个'])
这里有个细节:newline='' 必须加上。如果不加,Windows 系统下每行后面会多一个空行。我当年第一次写 CSV 时就被这个坑过,输出文件打开一看,行与行之间全是空行,尴尬得很。
DictWriter:按字典写入,自动对齐列
DictWriter 和 DictReader 是对称的。它需要你提前指定字段名列表,写入时自动按顺序对齐。
import csv
fieldnames = ['配方编号', '原料名称', '用量', '单位']
with open('output.csv', 'w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader() # 写入表头
writer.writerow({'配方编号': 'R002', '原料名称': '糖', '用量': '200', '单位': 'g'})
writer.writerow({'配方编号': 'R002', '原料名称': '鸡蛋', '用量': '3', '单位': '个'})
你想想看,如果字段有 20 个,用 writer 写列表你得记住每个位置对应什么。用 DictWriter 就省心多了,字典的键名一目了然,顺序由 fieldnames 统一控制。
四个核心类的对比
| 类名 | 输入/输出格式 | 是否自动处理表头 | 适用场景 |
|---|---|---|---|
reader |
列表 | 否 | 简单读取,字段少且固定 |
DictReader |
字典 | 是(第一行作为键) | 字段多、表头变化、需要按列名访问 |
writer |
列表 | 否 | 快速写入,字段顺序明确 |
DictWriter |
字典 | 是(需调用 writeheader) | 字段多、需要保证列顺序、数据来自字典 |
知识结构图:csv 模块核心脉络
下面这张图帮你理清四个类的关系和选择路径:
基本读写操作:几个实用技巧
除了上面四个类的用法,还有几个操作细节值得记住。
指定分隔符
CSV 不一定是逗号分隔。我遇到过用制表符、分号甚至竖线做分隔符的文件。这时可以指定 delimiter 参数:
reader = csv.reader(f, delimiter='\t') # 制表符分隔
writer = csv.writer(f, delimiter=';') # 分号分隔
处理引号嵌套
如果字段本身包含逗号或换行符,CSV 会用引号包裹。内置模块自动处理这些情况,你不需要额外操心。
# 假设 CSV 中有一行:R001,"面粉,高筋",500,g
# reader 会自动解析为:['R001', '面粉,高筋', '500', 'g']
写入时控制引号行为
quoting 参数可以控制什么时候加引号:
| 参数值 | 含义 | 常用场景 |
|---|---|---|
csv.QUOTE_MINIMAL |
只在必要时加引号(默认) | 通用场景 |
csv.QUOTE_ALL |
所有字段都加引号 | 数据可能包含特殊字符时 |
csv.QUOTE_NONNUMERIC |
非数字字段加引号 | 需要区分类型时 |
csv.QUOTE_NONE |
从不加引号 | 数据绝对干净时(不推荐) |
newline=''、注意表头空格、善用 delimiter 参数,基本就不会出大问题。