
这次我们来看 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追加写入modea向已有文件追加数据批量任务配合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 及以上。如果你是新环境先安装 Pandaspip install pandas如果你使用 AnacondaPandas 通常已经预装可以使用conda install pandas更新到需要的版本。安装完成后在 Python 交互环境或脚本里验证import pandas as pd print(pd.__version__)正常情况下会输出一个版本号。如果提示No module named pandas说明 Pandas 没有安装成功需要回到 pip 安装步骤并检查当前终端是不是对应你要用的 Python 环境。关于 PyCharm如果你用的是 PyCharm 社区版或专业版直接在下方 Terminal 执行 pip 安装即可。如果是在项目里配置了虚拟环境注意先激活虚拟环境再装依赖。准备测试文件时可以先手动创建一个简单的 csv。下面这段代码会在当前目录生成一个用于测试的students.csvimport pandas as pd demo_df pd.DataFrame({ name: [张三, 李四, 王五, 赵六], class: [一班, 二班, 一班, 三班], score: [88, 92, 76, 85] }) demo_df.to_csv(students.csv, indexFalse, encodingutf-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直接读取会出问题。文件没有表头要用headerNone配合names指定列名df pd.read_csv(students_no_header.csv, headerNone, names[姓名, 班级, 分数])如果没有namesPandas 会自动用0, 1, 2...作为列名后期处理很别扭。想跳过原始表头直接指定自己的列名df pd.read_csv(students.csv, header0, names[stu_name, stu_class, stu_score])这里header0表示跳过第一行原始表头用names替代。表头前面有无关行可以用skiprows跳过df pd.read_csv(messy.csv, skiprows2)这样会跳过文件最前面的 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_coldf pd.read_csv(students.csv, index_col0) print(df)输出class score name 张三 一班 88 李四 二班 92 王五 一班 76 赵六 三班 85index_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;)读取空格分隔但多个空格数量不一时用正则表达式\sdf pd.read_csv(students.txt, sepr\s)注意sep如果是正则表达式建议加上enginepython避免默认 C 引擎的兼容性限制df pd.read_csv(students.txt, sepr\s, enginepython)4.5 缺失值处理na_values 与 keep_default_nacsv 文件里缺失值可能表示为空字符串、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_naFalse)这个参数在做文本处理时比较有用但要注意关闭默认缺失值识别后空单元格会成为空字符串而不是NaN。4.6 数据类型指定dtypePandas 读取大文件时默认会自动推断每列类型。但自动推断有一个常见坑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, chunksize10000) for chunk in chunk_iter: # 对每一块做处理 print(chunk.shape)chunksize10000表示每次读取 1 万行。chunk_iter是一个可迭代对象每轮返回一个 DataFrame。如果需要统计一个大文件的行数不需要全部读入row_count 0 for chunk in pd.read_csv(big_data.csv, chunksize10000): 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是把文本读成 DataFrameto_csv是把 DataFrame 写回文本。方向相反坑也一样多。5.1 最简保存df.to_csv(output.csv)这样保存的结果会带上行索引生成的文件第一列是Unnamed: 0这是最常见的坑。绝大多数业务场景不需要行索引所以标准写法是df.to_csv(output.csv, indexFalse)5.2 控制索引与表头index控制是否写出行索引df.to_csv(output.csv, indexFalse)如果想保存索引又希望索引列有名字可以这样df.to_csv(output_with_index.csv, indexTrue)header控制是否写出列名# 不写表头常用于追加数据 df.to_csv(output.csv, headerFalse)5.3 解决 Excel 打开乱码encodingutf-8-sig中文数据保存为 csv 后用 Excel 打开经常显示乱码。原因通常是 Windows 版 Excel 对 UTF-8 不带 BOM 的识别有问题。解决方式是用utf-8-sig编码df.to_csv(students_utf8_sig.csv, indexFalse, encodingutf-8-sig)如果明确要和旧系统交换数据系统要求 GBK 编码可以这样写df.to_csv(students_gbk.csv, indexFalse, encodinggbk)读取时也要对应df pd.read_csv(students_gbk.csv, encodinggbk)5.4 只保存指定列如果 DataFrame 有很多列导出时只想保留部分列用columns参数df.to_csv(students_part.csv, columns[name, score], indexFalse)5.5 自定义分隔符输出想把 DataFrame 保存为 txt 或 tsv修改sepdf.to_csv(students.tsv, sep\t, indexFalse)如果不指定sep默认是逗号。5.6 追加写入modea向已有文件追加数据需要modea。追加时一般不需要表头new_data.to_csv(all_data.csv, modea, headerFalse, indexFalse)这里有几个要注意的点文件编码要和已有文件保持一致否则乱码列顺序要和已有表头一致否则数据错位。追加前最好先读取文件确认结构。5.7 压缩保存大数据量保存为 csv 后体积很大可以直接输出压缩包df.to_csv(students.csv.gz, indexFalse, compressiongzip)读取时read_csv自动识别df pd.read_csv(students.csv.gz)如果保存为 zipdf.to_csv(students.csv.zip, indexFalse, compressionzip)5.8 控制小数精度与缺失值表示浮点数导出时位数很长可以用float_format控制df.to_csv(students_float.csv, indexFalse, float_format%.2f)缺失值在 csv 文件中默认显示为空字符串想自定义df.to_csv(students_na.csv, indexFalse, na_repNULL)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, sepr\s)无表头 txt 文件df pd.read_csv(data.txt, sep\t, headerNone, names[col1, col2, col3])写出为 txtdf.to_csv(data.txt, sep\t, indexFalse)用sep统一处理 csv 和 txt是 Pandas 最方便的一点不需要学习两套 API。如果你拿到的文件扩展名是.data、.log、.dat只要内容结构是分隔符文本read_csv都能处理关键是找到正确的sep。7. 实战CSV 数据清洗后批量导出下面做一个完整的综合练习批量读取多个 csv 文件完成简单清洗再统一导出。假设./data/raw目录下有三个格式相同的 csv 文件每列包含name、score、remarkscore可能是字符串或缺失。用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, encodingutf-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], errorscoerce) df_list.append(df) result pd.concat(df_list, ignore_indexTrue) print(合并后总行数, len(result)) # 导出为 utf-8-sigExcel 直接打开不乱码 result.to_csv(output_path, indexFalse, encodingutf-8-sig, float_format%.2f) print(已导出, output_path)关键点glob.glob拿到目录下所有 csv 路径。na_values把-和NULL统一识别为缺失。drop_duplicates()删除完全重复的行。pd.to_numeric(errorscoerce)把无法转成数字的值变成NaN避免整列变成字符串。最后用utf-8-sig导出方便给同事用 Excel 打开。如果业务上要求每个原始文件单独输出一份清洗后的结果可以这样clean_dir ./data/clean os.makedirs(clean_dir, exist_okTrue) for file_path in file_list: df pd.read_csv(file_path, encodingutf-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, indexFalse, encodingutf-8-sig) print(保存, save_path)这个模式可以扩展到几百个文件核心思路是目录遍历、逐文件处理、命名规则统一。8. 常见问题与排查方法问题现象可能原因排查方式解决方案读取 csv 后中文乱码文件编码与指定编码不一致用文本编辑器打开看原始编码或用chardet判断读取时指定正确编码如encodinggbk导出的 csv 用 Excel 打开乱码保存时用了utf-8没有带 BOM用文本编辑器打开确认内容保存时使用encodingutf-8-sig第一列出现Unnamed: 0to_csv时没有设置indexFalse查看文件第一行列名保存时indexFalse读取报ParserError: Error tokenizing data文件列数不一致或有额外分隔符查看出错行打开文件确认分隔符指定sep加error_bad_linesFalse新版用on_bad_linesskip数字列读出来是字符串列中混入非数字字符或指定了错误 dtypedf.dtypes查看类型用pd.to_numeric(..., errorscoerce)转换前导 0 丢失读取时自动推断为数值类型查看列值长度读取时dtype{列名: str}读取大文件卡死或内存溢出一次性读入全部数据查看文件大小和内存使用chunksize分块读取追加写入后数据错位列顺序或分隔符不一致打开文件肉眼核对追加前统一列顺序headerFalse空值没有识别为 NaN自定义缺失标记未指定打印df.isna().sum()使用na_values指定标记文件路径含中文报错Windows 下编码处理问题查看报错信息使用原始字符串或pathlib.Path避免手写转义新版 Pandas 中error_bad_lines参数已经被移除替代方案是on_bad_linesdf pd.read_csv(messy.csv, on_bad_linesskip)9. 最佳实践与使用建议第一次读取新文件时先只读前几行看结构df_preview pd.read_csv(data.csv, nrows5) print(df_preview)nrows是排查文件格式问题的利器不用等大文件全部读入。不要直接改原始数据文件。清洗、转换后的结果另存一份保留原始文件作为数据源。文件目录区分raw、clean、output。原始数据、中间结果、最终交付分开放避免后续找不到谁是谁。批量处理一定要加日志或打印进度。文件少时无所谓几百个文件处理到一半中断没有日志会非常被动。追加写入前统一列名和顺序最好先检查目标文件是否存在以及是否为空。编码问题要在项目最开始就定好。团队内部统一 UTF-8 或 utf-8-sig和旧系统交换时单独导出 GBK 版本。涉及手机号、身份证号等敏感数据时导出 csv 前先做脱敏处理并限制文件的访问权限。大文件导出时可以考虑压缩格式df.to_csv(output.csv.gz, indexFalse, compressiongzip)如果数据量到了几千万行csv 已经不是最佳选择考虑 parquet、数据库或者分区存储。10. 总结与下一步read_csv和to_csv看起来简单实际用到项目里编码、表头、列类型、大文件、批量导出每一项都是细节。这次把最常用的参数和几个完整场景过了一遍下次写pd.read_csv(xxx.csv)之前先花十秒确认三件事文件是什么编码、有没有表头、分隔符是什么。三个问题想清楚能省下大量调试时间。如果想继续深入下一步可以看这几个方向Pandas 的read_excel和 Excel 多 Sheet 处理、merge和concat多表合并、groupby聚合统计、以及 Parquet 格式在大数据场景下的应用。建议把这篇里的示例代码在本地环境跑一遍然后拿自己手头真实数据做一次清洗导出练习几天后你会发现自己处理表格文件的效率有明显提升。建议收藏备用。