CSV 文件读写
本教程共 54 篇 · 第 11 篇 · 更新于 2026-08-11 · 约 8 分钟阅读
本节目标:掌握 read_csv 和 to_csv 的常用参数,能独立完成”读取 CSV → 处理 → 写回 CSV”的完整流程,包括编码和压缩文件等进阶场景。
CSV:最通用的表格文本格式
CSV(Comma-Separated Values,逗号分隔值)用纯文本存储表格:每行一条记录,字段之间用逗号隔开。打开任意一个 CSV 文件,你会看到:
姓名,年龄,城市
张三,25,北京
李四,30,上海
第一行是表头,后面每行是一条数据。它简单、通用,Excel 能打开,数据库能导出,各种编程语言都能处理,是数据交换的事实标准。
pandas 读写 CSV 就两个函数:读用 pd.read_csv(),写用 df.to_csv()。
第一次读取:read_csv
import pandas as pd
df = pd.read_csv("数据.csv")
print(df)
一行代码,CSV 就变成了 DataFrame。pandas 会自动完成三件事:
- 推断分隔符(默认逗号)
- 把第一行当作列名(表头)
- 为数据生成默认的 RangeIndex
想验证读取结果,用 df.head() 看前几行,或 df.info() 看列名、行数、dtype 总览。
Notepandas 3.0 读取字符串列时,dtype 显示为
str而不是object——新字符串类型已是默认(§07 讲过)。这不影响使用,但你可能注意到输出和旧教程不一样。
分隔符 sep:不只是逗号
CSV 的分隔符不一定是逗号。Windows 导出的中文数据常用制表符,欧洲数据常用分号。用 sep 指定:
df = pd.read_csv("数据.tsv", sep="\t") # 制表符分隔
df = pd.read_csv("数据.txt", sep=";") # 分号分隔
sep 不传时,pandas 默认按逗号解析;遇到其他分隔符会解析出错或变成一列,这时显式指定 sep 就好。delimiter 是 sep 的别名,效果一样。
为了下面的例子不依赖真实文件,我们用 StringIO 把字符串伪装成文件:
from io import StringIO
csv_data = """姓名,年龄,城市
张三,25,北京
李四,30,上海
"""
df = pd.read_csv(StringIO(csv_data))
print(df)
Tip想快速预览”到底用哪个分隔符”,可以用
sep=None让 pandas 自动嗅探(sniff)——注意只有engine="python"才支持。不过自动检测有时不准,正式代码还是显式指定最稳。
表头 header 与列名 names
默认第一行是表头。如果文件没有表头,传 header=None,pandas 会生成 0、1、2 这样的默认列名:
csv_data = """张三,25,北京
李四,30,上海
"""
df = pd.read_csv(StringIO(csv_data), header=None)
print(df.columns) # Index([0, 1, 2], dtype='int64')
想让列名更可读,用 names 指定:
df = pd.read_csv(StringIO(csv_data), header=None,
names=["姓名", "年龄", "城市"])
print(df)
还可以用 header=0 显式声明”第一行是表头”(默认行为),配合 names 可以覆盖文件里的原始列名:
df = pd.read_csv(StringIO(csv_data2), header=0,
names=["name", "age", "city"])
索引列 index_col
默认情况下,CSV 没有索引列,读进来是 RangeIndex。如果文件第一列本身是 ID,可以用 index_col 把它设为行索引:
csv_data = """编号,姓名,分数
S001,张三,85
S002,李四,92
"""
df = pd.read_csv(StringIO(csv_data), index_col=0)
print(df)
输出里”编号”变成了索引名,不再是一列数据。
有个特殊值 index_col=False:当文件每行末尾多了一个分隔符(比如 张三,25,北京,),pandas 可能误把第一列当索引。传 False 可以强制不做推断,直接生成 RangeIndex。
缺失值标记 na_values
CSV 里表示”没有数据”的方式五花八门:空字符串、NA、NULL、N/A、NaN……pandas 默认认识一大串常见标记(空串、NA、NULL、NaN、N/A 等),会自动转成 NaN。
数据源用了别的标记,用 na_values 补充:
csv_data = """姓名,分数
张三,85
李四,缺考
"""
df = pd.read_csv(StringIO(csv_data), na_values=["缺考", "未统计"])
print(df)
“缺考”和”未统计”会被当作缺失值。默认标记仍然生效,na_values 是追加。
想彻底重来,用 keep_default_na=False 关掉默认标记,只认你指定的:
df = pd.read_csv(StringIO(csv_data), keep_default_na=False,
na_values=["缺考"])
Warning读取解析阶段,空字符串默认也算缺失值。如果你的数据里空串有实际含义(比如表示”无”),记得用
keep_default_na=False调整,否则读进来全是 NaN。(注意这仅指 read_csv 解析阶段;数据读进内存后""本身不是缺失值,见 §25。)
其他高频参数
再记几个常用的,都放在一个例子里:
df = pd.read_csv("数据.csv",
usecols=["姓名", "分数"], # 只读这两列
dtype={"分数": "float64"}, # 强制列类型
skiprows=1, # 跳过前 1 行
nrows=100, # 只读前 100 行
encoding="utf-8") # 指定编码
逐个说明:
usecols:只读指定列,省内存、省时间dtype:字典指定每列类型,避免自动推断出错(比如”001”被读成 1)skiprows:跳过开头若干行(文件前面有说明文字时很管用)nrows:大数据先读几行看看结构encoding:中文文件经常是gbk编码,乱码时试试encoding="gbk"
日期列可以配 parse_dates:pd.read_csv("数据.csv", parse_dates=["日期"]) 会自动把日期列转成 datetime64 类型。数字里的千分位逗号(1,234)可以用 thousands="," 处理。
编码:中文乱码怎么办
CSV 文件本身不记录编码信息。Windows 上 Excel 导出的中文 CSV 常用 gbk 编码,直接按默认的 utf-8 读,轻则乱码,重则直接报 UnicodeDecodeError:
df = pd.read_csv("中文数据.csv", encoding="gbk")
拿不准编码时,可以加 errors="replace" 兜底——解析不了的字符替换成占位符,程序至少不崩:
df = pd.read_csv("中文数据.csv", encoding="gbk", errors="replace")
写文件同理:to_csv(encoding="utf-8") 写出的文件,用 Excel 双击打开可能乱码(Excel 默认按 gbk 猜)。要么写入时用 gbk,要么在 Excel 里用”数据 → 从文本/CSV”导入并手动选 utf-8。
直接读 URL 和压缩文件
read_csv 的路径参数很宽容:支持 http(s) 链接,也支持压缩文件,压缩格式按扩展名自动识别(.gz、.bz2、.zip、.xz),不用手动解压:
df = pd.read_csv("https://example.com/data.csv") # 远程 URL
df = pd.read_csv("data.csv.gz") # gzip 压缩
df = pd.read_csv("data.zip") # zip 压缩
读远程文件要注意网络可能慢、可能失败,高频访问的接口建议先下载到本地缓存。压缩文件的好处是省磁盘、省流量,读取速度反而更快(解压是 C 级别的,很快)。
写出:to_csv
to_csv 的用法和 read_csv 对称:
df.to_csv("输出.csv") # 基本写法
df.to_csv("输出.csv", index=False) # 不写行索引(最常见)
index=False 是你最该记住的参数。 默认情况下,to_csv 会把行索引也写进去,生成一个多余的 index 列。绝大多数场景你都不想要它。
再看一组参数:
df.to_csv("输出.csv",
index=False, # 不写索引
columns=["姓名", "分数"], # 只写这两列
sep=";", # 分号分隔
na_rep="缺失", # 缺失值写成"缺失"
encoding="utf-8", # 编码
float_format="%.2f") # 浮点数保留两位
columns:只导出指定列na_rep:NaN 在文件里的表示,默认空串float_format:控制浮点数的格式mode="a":追加模式,把数据接到文件末尾(默认是w覆盖)
写完再读回来验证,是养成习惯的好方法:
df2 = pd.read_csv("输出.csv")
print(df2.head())
小结
read_csv读文件,to_csv写文件,两者参数一一对应- 分隔符用
sep:逗号、制表符、分号都能处理 - 表头用
header控制,自定义列名用names - 索引列用
index_col,index_col=False对付畸形文件 - 缺失标记用
na_values追加、keep_default_na=False重置 usecols、dtype、skiprows、nrows、encoding是高频搭配- 中文乱码先试
encoding="gbk";URL 和压缩文件直接读 - 写文件记得
index=False,多半你不需要索引列
下一节读 Excel 文件,参数和 CSV 大同小异,但多了一个”sheet”的概念。