导出csv中文乱码应使用encoding='utf_8_sig';to_excel报错需安装openpyxl;日期显示为数字需设置单元格格式或转字符串;大文件应分块导出以避免内存溢出。

导出CSV时中文乱码怎么办
Windows系统下用 pandas.to_csv() 默认用 utf-8 编码,但Excel(尤其是旧版)打开会显示乱码,本质是它默认按 gbk 解码。不是数据错了,是编码和解码不匹配。
解决方法很简单:显式指定 encoding='utf_8_sig' —— 这个编码会在文件开头加BOM头,让Excel认出是UTF-8:
df.to_csv('output.csv', encoding='utf_8_sig', index=False)
注意别写成 'utf-8-sig'(带短横线),pandas只认 'utf_8_sig';也别用 gbk,虽然能打开,但会丢掉 emoji、生僻字或英文特殊符号。
- Mac/Linux用户一般不用加
encoding,系统原生支持UTF-8 - 如果下游是Python脚本读取,保持
utf-8即可,不必加_sig -
index=False建议始终加上,否则多一列行号,容易被误当数据
to_excel() 报错“ModuleNotFoundError: No module named 'openpyxl'”
pandas.to_excel() 本身不自带引擎,依赖第三方库。报这个错,说明没装 openpyxl(处理 .xlsx)或 xlsxwriter(也可用,但功能略少)。
直接装就行:
pip install openpyxl
装完不用改代码,pandas会自动选用 openpyxl。如果已装还报错,检查是否在虚拟环境中漏装,或用了 conda 装的 pandas 却 pip 装的 openpyxl(环境不一致)。
- 只导出 .xls(老格式)才需要
xlwt,现在基本不用,别踩坑 - 想控制样式(如加粗、冻结窗格),
openpyxl是唯一选择;xlsxwriter不支持读取已有文件 - 大数据量(>10万行)导出 Excel 会明显变慢,CSV 更稳
日期列导出后在Excel里变成数字
pandas 的 datetime64 类型导出到Excel时,有时显示成一串数字(如 44562.0),这是Excel把时间当成了“自1900-01-01起的天数”。不是bug,是格式没设对。
根本解法是在保存前统一转为字符串,或导出后在Excel里设单元格格式为“日期”。更稳妥的做法是用 openpyxl 引擎手动控制列格式:
with pd.ExcelWriter('output.xlsx', engine='openpyxl') as writer:
df.to_excel(writer, index=False)
# 获取工作表对象
ws = writer.sheets['Sheet1']
# 假设第2列是日期,从第2行开始(第1行是标题)
for row in ws.iter_rows(min_row=2, min_col=2, max_col=2):
for cell in row:
cell.number_format = 'yyyy-mm-dd'
如果只是临时导出看一眼,导出后在Excel里选中列 → 右键“设置单元格格式” → “日期”,比写代码快得多。
- 用
dt.strftime('%Y-%m-%d')转字符串也能避免问题,但会丢失 datetime 类型信息 - 含时分秒的列建议用
'yyyy-mm-dd hh:mm:ss'格式,不然Excel可能截断 - 导出前用
df.dtypes确认列类型,别靠肉眼猜
大文件导出卡死或内存爆掉
单次调用 to_csv() 或 to_excel() 会把整个 DataFrame 加载进内存再写入磁盘。1GB以上的数据很容易触发 OOM 或卡住。
拆成块写是最实用的方案:
# CSV 分块导出(自动追加,首块写列名,后续不写)
for i, chunk in enumerate(pd.read_csv('input.csv', chunksize=50000)):
chunk_processed = your_processing_func(chunk)
mode = 'w' if i == 0 else 'a'
header = i == 0
chunk_processed.to_csv('output.csv', mode=mode, header=header, index=False, encoding='utf_8_sig')
Excel 不支持追加写入,所以大文件优先选 CSV;真要 Excel,就分 Sheet 写:
with pd.ExcelWriter('output.xlsx') as writer:
for i, chunk in enumerate(np.array_split(df, 10)): # 拆10份
chunk.to_excel(writer, sheet_name=f'Sheet_{i+1}', index=False)
- chunksize 太小(如1000)会导致IO频繁,太大会失去意义;5万~10万是常见平衡点
- Excel 单 Sheet 行数上限是1048576,超了必须分 Sheet 或换 CSV
- 导出前删掉无用列:
df = df[['col_a', 'col_b']],省内存也提速
导出看似简单,但编码、引擎、类型、规模这四个点,任何一个没对齐,就会在下游环节突然冒泡——而且往往出现在你最不想调试的时候。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











