☰
Pandas读写CSV/TXT文件:read_csv与to_csv参数详解与实战
2026/10/13 4:09:49 网站建设 项目流程

这次我们来看 Pandas 读写 txt 和 csv 文件。做数据分析的同学应该都有同感:read_csv和to_csv几乎是每天都要碰的函数,但大多数人的用法停留在最简单的“读进来、存出去”。一旦遇到表头缺失、编码乱码、分隔符不是逗号、大文件内存不够、批量导出命名冲突这些问题,又开始翻文档、搜百度,一上午就没了。

这篇文章把read_csv和to_csv的常用参数、典型场景和坑位一次讲透,全部围绕真实数据分析流程来写。你不仅能看懂每个参数是干什么的,还能直接复制代码改路径跑起来,从基础读取到批量处理一条线打通。

文章会覆盖这些内容:Pandas 核心能力速览、环境准备、read_csv参数详解(表头、列筛选、索引列、分隔符、缺失值、类型、分块读取)、to_csv参数详解(索引控制、编码、追加、压缩、精度控制)、TXT 文件读写、完整实战案例、常见问题排查、工程化建议。

1. Pandas 读写能力速览

先给出一张总览表,后面所有内容都围绕这张表展开。

能力项说明
核心函数read_csv、to_csv,可同时处理 csv 和 txt
支持的文本格式csv(逗号分隔)、tsv(制表符分隔)、空格/正则分隔符文本
文件编码UTF-8、GBK、GB2312、utf-8-sig 等,通过encoding参数指定
表头处理自动识别表头、无表头指定names、跳过表头
列筛选usecols按列名或列下标读取指定列
索引列index_col指定某一列作为行索引
缺失值处理na_values自定义缺失值标记,na_rep控制写出占位
大文件处理chunksize分块迭代,避免一次性读入内存
数据写出保存为 csv、txt、压缩包(gzip/zip)
追加写入mode='a'向已有文件追加数据
批量任务配合glob/pathlib批量读取和命名导出
API 能力read_csv支持从 URL、文件对象直接读取
学习成本参数多,但核心掌握十来个就够解决 95% 场景

材料里的热搜词集中在“python 读取 csv”“pandas 导入 csv”“pandas 转换数据类型”“csv 保存”等方向,说明这是新手到进阶都会卡住的点。这篇文章的目标是让你看完之后,处理日常 csv/txt 文件不再求人。

2. 适用场景与使用边界

read_csv和to_csv适合这些场景:

  • 读取 Excel 另存的 csv 文件、数据库导出的 csv 文件、爬虫抓取的表格数据。
  • 把清洗、聚合、转换后的 DataFrame 保存为 csv 给其他同事或系统使用。
  • 批量合并多个结构相同的 csv 文件。
  • 跨系统交换数据,csv 是最低门槛的通用格式。
  • 保存模型特征工程中间结果、训练集切分结果、日志解析结果。
  • 读取部分业务系统生成的 txt 日志、空格分隔的文本数据。

不适合或需要小心的场景:

  • 文件超过几个 GB 时,直接pd.read_csv()容易内存爆炸,要用分块或换用 Polars、Dask、数据库。
  • 数据包含复杂嵌套结构(如 JSON 里套数组),csv 不适合表达这种层级关系。
  • 需要频繁随机读写和更新单行数据时,应该用数据库或 parquet。
  • 数据量很大且需要长期分析时,parquet 比 csv 更省空间、读写更快。
  • 涉及用户隐私数据、商业数据时,导出的 csv 要注意脱敏、访问权限和加密存储,不能把手机号、身份证等敏感字段明文丢在共享目录里。

csv 文件的本质是纯文本,虽然简单,但编码、换行符、分隔符、转义规则都会带来坑。后续每一节都会针对这些边界给出具体处理方式。

3. 环境准备与前置条件

在动手之前,先确认环境。

操作系统方面,Windows、Linux、macOS 都可以,命令只有微小的平台差异。Python 版本建议 3.8 及以上。如果你是新环境,先安装 Pandas:

pip install pandas

如果你使用 Anaconda,Pandas 通常已经预装,可以使用conda install pandas更新到需要的版本。安装完成后,在 Python 交互环境或脚本里验证:

import pandas as pd print(pd.__version__)

正常情况下会输出一个版本号。如果提示No module named 'pandas',说明 Pandas 没有安装成功,需要回到 pip 安装步骤,并检查当前终端是不是对应你要用的 Python 环境。

关于 PyCharm,如果你用的是 PyCharm 社区版或专业版,直接在下方 Terminal 执行 pip 安装即可。如果是在项目里配置了虚拟环境,注意先激活虚拟环境再装依赖。

准备测试文件时,可以先手动创建一个简单的 csv。下面这段代码会在当前目录生成一个用于测试的students.csv:

import pandas as pd demo_df = pd.DataFrame({ "name": ["张三", "李四", "王五", "赵六"], "class": ["一班", "二班", "一班", "三班"], "score": [88, 92, 76, 85] }) demo_df.to_csv("students.csv", index=False, encoding="utf-8") print("测试文件已生成")

运行后,目录下会多出一个students.csv,后面的示例都基于这个文件展开。

4. read_csv 基础读取与参数详解

这一节是重点。pd.read_csv()的参数非常多,但实际项目里高频使用的是下面这些,我按功能分组讲。

4.1 最简读取

import pandas as pd df = pd.read_csv("students.csv") print(df)

输出:

name class score 0 张三 一班 88 1 李四 二班 92 2 王五 一班 76 3 赵六 三班 85

默认行为是:第一行作为列名,后续行作为数据,自动生成从 0 开始的行索引。如果你的文件就是标准 csv,这样写就够了。

4.2 处理表头:header 和 names

实际场景中,很多 csv 文件没有表头,或者表头是中文、带空格、带 BOM,直接读取会出问题。

文件没有表头,要用header=None配合names指定列名:

df = pd.read_csv("students_no_header.csv", header=None, names=["姓名", "班级", "分数"])

如果没有names,Pandas 会自动用0, 1, 2...作为列名,后期处理很别扭。

想跳过原始表头,直接指定自己的列名:

df = pd.read_csv("students.csv", header=0, names=["stu_name", "stu_class", "stu_score"])

这里header=0表示跳过第一行原始表头,用names替代。

表头前面有无关行,可以用skiprows跳过:

df = pd.read_csv("messy.csv", skiprows=2)

这样会跳过文件最前面的 2 行,然后自动识别新表头。

4.3 指定列与索引列

一个 csv 可能有几十列,但你只需要其中几列。全量读入再用df[["列名"]]筛选,会浪费内存和时间。usecols可以直接在读取阶段筛选:

df = pd.read_csv("students.csv", usecols=["name", "score"])

也可以按列下标筛选,比如读取第 0 列和第 2 列:

df = pd.read_csv("students.csv", usecols=[0, 2])

这个参数在处理宽表时非常实用。

如果希望某一列成为 DataFrame 的行索引,用index_col:

df = pd.read_csv("students.csv", index_col=0) print(df)

输出:

class score name 张三 一班 88 李四 二班 92 王五 一班 76 赵六 三班 85

index_col可以传列名,也可以传下标。多级索引时还可以传列表,如index_col=["year", "month"],但日常少用。

4.4 分隔符:sep 与正则表达式

csv 的“c”是 comma,但现实里的文本文件分隔符五花八门:制表符、空格、分号、竖线。用sep参数解决。

读取制表符分隔的 txt 文件:

df = pd.read_csv("students.tsv", sep="\t")

读取分号分隔的文件:

df = pd.read_csv("students_semicolon.csv", sep=";")

读取空格分隔,但多个空格数量不一时,用正则表达式\s+:

df = pd.read_csv("students.txt", sep=r"\s+")

注意:sep如果是正则表达式,建议加上engine='python',避免默认 C 引擎的兼容性限制:

df = pd.read_csv("students.txt", sep=r"\s+", engine="python")

4.5 缺失值处理:na_values 与 keep_default_na

csv 文件里缺失值可能表示为空字符串、NA、NULL、N/A、-等。Pandas 默认把空字符串、NA、NaN等识别为缺失值,但自定义标记需要手动指定:

df = pd.read_csv("students_with_na.csv", na_values=["NA", "NULL", "-"])

这样文件里的-就会变成NaN,后续dropna()、fillna()才能正确处理。

如果你不想让 Pandas 把空字符串当缺失值,而是保留为普通字符串,可以设置:

df = pd.read_csv("students.csv", keep_default_na=False)

这个参数在做文本处理时比较有用,但要注意,关闭默认缺失值识别后,空单元格会成为空字符串,而不是NaN。

4.6 数据类型指定:dtype

Pandas 读取大文件时,默认会自动推断每列类型。但自动推断有一个常见坑:id列明明是一串数字,但某些行前导 0 被自动忽略了;或者某列大部分是数字,中间混入少量文本,整个列变成object。

这时用dtype强制指定:

df = pd.read_csv("students.csv", dtype={"score": float, "name": str})

实际业务里最典型的是手机号、学号、身份证号、订单号:

df = pd.read_csv("users.csv", dtype={"phone": str, "user_id": str})

如果不指定,phone列里前导 0 会被丢掉,后面匹配和展示时就出大问题。

dtype还有一个好处:可以避免大文件读取时自动类型推断额外消耗的时间。converters参数适合做列级转换,比如把字符串转成日期,但parse_dates通常更直接:

df = pd.read_csv("sales.csv", parse_dates=["order_date"])

4.7 大文件分块读取:chunksize

当文件大到几 GB 时,一次pd.read_csv()会占满内存,直接卡死。正确做法是分块读取:

chunk_iter = pd.read_csv("big_data.csv", chunksize=10000) for chunk in chunk_iter: # 对每一块做处理 print(chunk.shape)

chunksize=10000表示每次读取 1 万行。chunk_iter是一个可迭代对象,每轮返回一个 DataFrame。

如果需要统计一个大文件的行数,不需要全部读入:

row_count = 0 for chunk in pd.read_csv("big_data.csv", chunksize=10000): row_count += len(chunk) print(row_count)

如果文件特别大,又只需要部分列,配合usecols可以减少内存占用。

4.8 读取网络 URL 文件

read_csv可以直接读取网络地址:

url = "https://example.com/data.csv" df = pd.read_csv(url)

不过在国内访问外部地址可能不稳定,更稳妥的做法是先下载到本地再读取。频繁请求时要注意目标网站的使用条款和访问频率。

5. to_csv 保存数据与参数实战

read_csv是把文本读成 DataFrame,to_csv是把 DataFrame 写回文本。方向相反,坑也一样多。

5.1 最简保存

df.to_csv("output.csv")

这样保存的结果会带上行索引,生成的文件第一列是Unnamed: 0,这是最常见的坑。绝大多数业务场景不需要行索引,所以标准写法是:

df.to_csv("output.csv", index=False)

5.2 控制索引与表头

index控制是否写出行索引:

df.to_csv("output.csv", index=False)

如果想保存索引,又希望索引列有名字,可以这样:

df.to_csv("output_with_index.csv", index=True)

header控制是否写出列名:

# 不写表头,常用于追加数据 df.to_csv("output.csv", header=False)

5.3 解决 Excel 打开乱码:encoding="utf-8-sig"

中文数据保存为 csv 后,用 Excel 打开经常显示乱码。原因通常是 Windows 版 Excel 对 UTF-8 不带 BOM 的识别有问题。解决方式是用utf-8-sig编码:

df.to_csv("students_utf8_sig.csv", index=False, encoding="utf-8-sig")

如果明确要和旧系统交换数据,系统要求 GBK 编码,可以这样写:

df.to_csv("students_gbk.csv", index=False, encoding="gbk")

读取时也要对应:

df = pd.read_csv("students_gbk.csv", encoding="gbk")

5.4 只保存指定列

如果 DataFrame 有很多列,导出时只想保留部分列,用columns参数:

df.to_csv("students_part.csv", columns=["name", "score"], index=False)

5.5 自定义分隔符输出

想把 DataFrame 保存为 txt 或 tsv,修改sep:

df.to_csv("students.tsv", sep="\t", index=False)

如果不指定sep,默认是逗号。

5.6 追加写入:mode="a"

向已有文件追加数据,需要mode="a"。追加时一般不需要表头:

new_data.to_csv("all_data.csv", mode="a", header=False, index=False)

这里有几个要注意的点:文件编码要和已有文件保持一致,否则乱码;列顺序要和已有表头一致,否则数据错位。追加前最好先读取文件确认结构。

5.7 压缩保存

大数据量保存为 csv 后体积很大,可以直接输出压缩包:

df.to_csv("students.csv.gz", index=False, compression="gzip")

读取时read_csv自动识别:

df = pd.read_csv("students.csv.gz")

如果保存为 zip:

df.to_csv("students.csv.zip", index=False, compression="zip")

5.8 控制小数精度与缺失值表示

浮点数导出时位数很长,可以用float_format控制:

df.to_csv("students_float.csv", index=False, float_format="%.2f")

缺失值在 csv 文件中默认显示为空字符串,想自定义:

df.to_csv("students_na.csv", index=False, na_rep="NULL")

6. 读写 TXT 文件:read_table 与 sep 配合

Pandas 没有单独的read_txt,读写 txt 文件仍然是复用read_csv/to_csv,只是换分隔符而已。

最常见的 txt 数据有两种:制表符分隔、空格分隔。

制表符分隔文件:

df = pd.read_csv("data.tsv", sep="\t")

空格分隔文件,且列之间可能有多个空格:

df = pd.read_csv("data.txt", sep=r"\s+")

无表头 txt 文件:

df = pd.read_csv("data.txt", sep="\t", header=None, names=["col1", "col2", "col3"])

写出为 txt:

df.to_csv("data.txt", sep="\t", index=False)

用sep统一处理 csv 和 txt,是 Pandas 最方便的一点:不需要学习两套 API。

如果你拿到的文件扩展名是.data、.log、.dat,只要内容结构是分隔符文本,read_csv都能处理,关键是找到正确的sep。

7. 实战:CSV 数据清洗后批量导出

下面做一个完整的综合练习:批量读取多个 csv 文件,完成简单清洗,再统一导出。

假设./data/raw目录下有三个格式相同的 csv 文件,每列包含name、score、remark,score可能是字符串或缺失。用glob配合 Pandas 处理:

import pandas as pd import glob import os input_dir = "./data/raw" output_path = "./data/clean/all_result.csv" file_list = glob.glob(os.path.join(input_dir, "*.csv")) print("找到文件数量:", len(file_list)) df_list = [] for file_path in file_list: df = pd.read_csv(file_path, encoding="utf-8", dtype={"name": str}, na_values=["-", "NULL"]) # 去除空白列名 df.columns = df.columns.str.strip() # 删除完全重复的行 df = df.drop_duplicates() # score 转数值,错误值变成 NaN df["score"] = pd.to_numeric(df["score"], errors="coerce") df_list.append(df) result = pd.concat(df_list, ignore_index=True) print("合并后总行数:", len(result)) # 导出为 utf-8-sig,Excel 直接打开不乱码 result.to_csv(output_path, index=False, encoding="utf-8-sig", float_format="%.2f") print("已导出:", output_path)

关键点:

  • glob.glob拿到目录下所有 csv 路径。
  • na_values把-和NULL统一识别为缺失。
  • drop_duplicates()删除完全重复的行。
  • pd.to_numeric(errors="coerce")把无法转成数字的值变成NaN,避免整列变成字符串。
  • 最后用utf-8-sig导出,方便给同事用 Excel 打开。

如果业务上要求每个原始文件单独输出一份清洗后的结果,可以这样:

clean_dir = "./data/clean" os.makedirs(clean_dir, exist_ok=True) for file_path in file_list: df = pd.read_csv(file_path, encoding="utf-8") df.columns = df.columns.str.strip() df = df.drop_duplicates() base_name = os.path.basename(file_path) save_path = os.path.join(clean_dir, "clean_" + base_name) df.to_csv(save_path, index=False, encoding="utf-8-sig") print("保存:", save_path)

这个模式可以扩展到几百个文件,核心思路是:目录遍历、逐文件处理、命名规则统一。

8. 常见问题与排查方法

问题现象可能原因排查方式解决方案
读取 csv 后中文乱码文件编码与指定编码不一致用文本编辑器打开看原始编码,或用chardet判断读取时指定正确编码,如encoding="gbk"
导出的 csv 用 Excel 打开乱码保存时用了utf-8,没有带 BOM用文本编辑器打开确认内容保存时使用encoding="utf-8-sig"
第一列出现Unnamed: 0to_csv时没有设置index=False查看文件第一行列名保存时index=False
读取报ParserError: Error tokenizing data文件列数不一致,或有额外分隔符查看出错行;打开文件确认分隔符指定sep,加error_bad_lines=False(新版用on_bad_lines='skip')
数字列读出来是字符串列中混入非数字字符,或指定了错误 dtypedf.dtypes查看类型用pd.to_numeric(..., errors="coerce")转换
前导 0 丢失读取时自动推断为数值类型查看列值长度读取时dtype={"列名": str}
读取大文件卡死或内存溢出一次性读入全部数据查看文件大小和内存使用chunksize分块读取
追加写入后数据错位列顺序或分隔符不一致打开文件肉眼核对追加前统一列顺序,header=False
空值没有识别为 NaN自定义缺失标记未指定打印df.isna().sum()使用na_values指定标记
文件路径含中文报错Windows 下编码处理问题查看报错信息使用原始字符串或pathlib.Path,避免手写转义

新版 Pandas 中,error_bad_lines参数已经被移除,替代方案是on_bad_lines:

df = pd.read_csv("messy.csv", on_bad_lines="skip")

9. 最佳实践与使用建议

  • 第一次读取新文件时,先只读前几行看结构:
df_preview = pd.read_csv("data.csv", nrows=5) print(df_preview)

nrows是排查文件格式问题的利器,不用等大文件全部读入。

  • 不要直接改原始数据文件。清洗、转换后的结果另存一份,保留原始文件作为数据源。

  • 文件目录区分raw、clean、output。原始数据、中间结果、最终交付分开放,避免后续找不到谁是谁。

  • 批量处理一定要加日志或打印进度。文件少时无所谓,几百个文件处理到一半中断,没有日志会非常被动。

  • 追加写入前统一列名和顺序,最好先检查目标文件是否存在以及是否为空。

  • 编码问题要在项目最开始就定好。团队内部统一 UTF-8 或 utf-8-sig,和旧系统交换时单独导出 GBK 版本。

  • 涉及手机号、身份证号等敏感数据时,导出 csv 前先做脱敏处理,并限制文件的访问权限。

  • 大文件导出时可以考虑压缩格式:

df.to_csv("output.csv.gz", index=False, compression="gzip")
  • 如果数据量到了几千万行,csv 已经不是最佳选择,考虑 parquet、数据库或者分区存储。

10. 总结与下一步

read_csv和to_csv看起来简单,实际用到项目里,编码、表头、列类型、大文件、批量导出,每一项都是细节。这次把最常用的参数和几个完整场景过了一遍,下次写pd.read_csv("xxx.csv")之前,先花十秒确认三件事:文件是什么编码、有没有表头、分隔符是什么。三个问题想清楚,能省下大量调试时间。

如果想继续深入,下一步可以看这几个方向:Pandas 的read_excel和 Excel 多 Sheet 处理、merge和concat多表合并、groupby聚合统计、以及 Parquet 格式在大数据场景下的应用。建议把这篇里的示例代码在本地环境跑一遍,然后拿自己手头真实数据做一次清洗导出练习,几天后你会发现自己处理表格文件的效率有明显提升。建议收藏备用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询