CSV 打开是乱码:编码判断、公式注入与导入 Excel 的完整排查

CSV 乱码的根因只有一个——写文件和读文件用了不同编码。本文给一张「乱码症状反查真实编码」的对照表、Excel 导入的分隔符与列类型设置、以及公式注入(= + - @ 开头)的两种堵法,按顺序走一遍基本都能定位。

约 8 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证

乱码只有一个根因:写文件和读文件用了不同的编码

「锟斤拷」「测è¿」「��」这些看着像损坏的字符,其实每一个字节都是对的,只是被按错误的字符集解码了。UTF-8 的中文占 3 个字节,GBK 占 2 个;拿 GBK 的规则去读 UTF-8 的字节,中文就会变成一串拉丁字母和符号。所以排查永远从一件事开始:这个文件当初是用什么编码写出来的,而不是先怀疑文件损坏。

乱码症状反查真实编码:一张对照表

把看到的乱码形态当成指纹去反查,比逐个试编码快得多。中文 Windows 的 Excel 和国产数据库导出常用 GBK/GB18030,而跨平台系统默认 UTF-8,两边撞车就出乱码。

你看到的乱码真实编码典型来源修复动作
锟斤拷 / 烫烫烫UTF-8 被当 GBK 读,又被二次转存UTF-8 文本在旧 Windows 记事本里改存按 UTF-8 重新读出,再用 UTF-8 存回去
飨 这类拉丁串UTF-8 被当 Latin-1 / ISO-8859-1 读HTTP 响应头没声明 charset,默认按 Latin-1响应头加 charset=utf-8
测è¿ä¸­æ–‡UTF-8 被当 GBK 读(最常见)Linux 导出 CSV 用 Excel 打开导入时手动指定 UTF-8,或导出时加 BOM
� 单个替换字符字节序列在当前编码里无对应字符文件被截断,或声明与实际编码不符确认文件完整并核对真实编码
第一行中文正常,从某行起乱文件内混了两种编码多次追加写入,日志与 CSV 拼接按行定位后整段重新转码
中文正常但引号变成 “UTF-8 被当 GBK 读后再存成 UTF-8经过一层错误的转码工具对全文做一次「误解码 → 重编码」还原
同一个文件,三种读法三种结果
原始字节(UTF-8):  e4 bd a0 e5 a5 bd          → 你好
按 UTF-8 读:        正常              → 你好
按 GBK 读:          e4bd=ä½  a0e5=¥  a5bd=½£  → ä½¥½£
按 GBK 读再存 UTF-8: 多了一层错误转码,之后每次修都在错上加错
Excel 认不出无 BOM 的 UTF-8 时的两个选择
① 导出时加 BOM:  \xEF\xBB\xBF + 内容   (Excel 双击即正确,脚本读时记得剥掉 BOM)
② 导入时手动指定: 数据 → 从文本/CSV → 原始文件选「65001: Unicode (UTF-8)」,分隔符选逗号

导入 Excel:分隔符、编码、列类型是三件独立的事

同一个双击动作背后,Excel 至少要猜三件事:文件是什么编码、字段用什么符号分隔、每列按什么类型解析。猜错任何一件都会得到「看起来导入成功但数据是错的」的结果,而 Excel 不会给你提示。所以稳妥的做法是走「数据 → 从文本/CSV」向导,把三件事都显式指定。

  1. 先在 Excel 里点「数据 → 从文本/CSV」,不要直接双击文件——双击走的是猜路径,向导才是可控路径。
  2. 「原始文件」下拉里选 65001 (UTF-8) 或对应代码页,别用「自动检测」,自动检测对短文件经常判错。
  3. 「分隔符」勾逗号;如果首行整行挤在一列,说明实际用的是分号或 Tab(常见于欧洲 locale 导出),勾上对应符号即可。
  4. 逐列点表头指定类型:身份证号、手机号、订单号必须选「文本」,否则 0012345 会被吃掉前导零,15 位以上数字会被转成科学计数法。
  5. 日期列如果导出成 2026/3/4 这种斜杠格式,指定日期类型并选对区域格式(YYYY/MM/DD),否则可能按日/月读反。
  6. 预览区行数正常但导入后行数变少,检查是否有字段内的换行符——未加引号的换行会把一条记录劈成两行。

公式注入:一个单元格能变成一条命令

CSV 是纯文本,但 Excel 会主动解释内容。以 =、+、-、@ 开头的单元格,导入后会被当成公式而不是字符串,于是「=1+1」显示 2,「=HYPERLINK(...)」变成可点击的链接。更危险的是从 CSV 里读 DDE 命令的构造,在某些客户端上能触发外部程序调用。触发条件很简单:文件来自不可信的来源,且原样双击打开。

两种堵法:导入时当文本读,导出时给危险前缀加一层

  • 导入侧:在向导的预览区把可疑列的类型强制选成「文本」,公式就只会显示为字符串,不会被求值。这是最省事的一招。
  • 导入侧:整表用「数据 → 从文本」并勾选「将文本转换为数字」时,把分隔符行结束符设成制表符,让整行被当成一个文本列。
  • 导出侧:所有以 = + - @ 开头的值,前面加一个单引号或一个制表符,写入时 Excel 就当纯文本。
  • 导出侧:值本身是数字但不希望被当数字解析时(如带前导零的编码),给它加 ="" 包裹或统一加单引号前缀。
  • 系统侧:不要用「启用所有数据连接」和 DDE 相关的旧设置;组策略里可以禁止从 CSV 触发 DDE,这是企业环境最有效的一刀。

结构层的三个坑:内嵌分隔符、换行与引号

坑数据长什么样为什么坏正确写法
字段里有逗号张伟,销售部,上海被切成三列,后面全部错位整字段用双引号包起来:"张伟,销售部,上海"
字段里有换行第一行 备注:待处理一条记录被拆成两行引号内允许换行,解析器会正确还原
字段里有双引号他说"好的"引号提前闭合,尾部变乱码双引号写成两个:""他说""好的"""
字段前后有空格上海 , 销售部肉眼难辨的去留差异导致 join 失败解析后统一 trim,别依赖原始空格
行尾符混用部分行 \r\n,部分行 \n部分解析器把 \r 当成内容导出时统一为 \n(或统一 \r\n)
BOM 混在数据里第一列名变成 \ufeffid字段名对不上,SQL 里找不到该列导出加 BOM,脚本读取时用 utf-8-sig

中文数据还多一层:全角符号与不可见字符

从 Word、公众号或网页复制来的表格,字段里常混着全角逗号(,)、全角冒号(:)、不间断空格(U+00A0)和零宽字符(U+200B)。全角逗号在 CSV 里不是分隔符,会被原样留在字段内,于是「看起来分隔正确但列数对不上」;不间断空格的字节是 0xC2 0xA0,肉眼与普通空格一模一样,但比较字符串时永远不相等。清洗的做法是先统一全角标点为半角,再把 U+00A0 和 U+200B 显式删除或替换成普通空格。

按这个顺序排查,五步定位乱码与错位

  1. 判断是编码问题还是分隔问题:如果中文能显示成别的文字,是编码;如果中文干脆不见了或整行挤在一列,是分隔符。
  2. 确认真实编码:把内容粘进编码修复工具,指定候选编码试解,能读回正常中文的那个就是原编码。
  3. 列出分隔符与行尾符的真实情况:不要凭肉眼,用文本统计类工具看行数、字符集和首行内容,确认是逗号、分号还是 Tab。
  4. 检查列数是否稳定:任取几行数字段数,若不一致,问题在引号或内嵌换行,而不是编码。
  5. 最后再管安全:把不可信来源的列按文本导入,或在导出时给 = + - @ 开头的值加前缀。

常见问题

Excel 打开 CSV 中文乱码,怎么确定是 UTF-8 还是 GBK?

最快的办法是不用 Excel 猜:把文件内容粘进 乱码修复工具,依次选 UTF-8 和 GBK 试解,能还原出正常中文的那个就是原编码。想让 Excel 双击直接正确,导出时加 UTF-8 BOM;导出给程序读则相反,不要加 BOM。

CSV 里的公式注入到底有多危险,需要防吗?

需要。风险不在「文件会不会自动执行」,而在「人双击打开」这个动作:以 = + - @ 开头的字段会被 Excel 求值,DDE 构造在部分客户端上能拉起外部程序。最省事的防线是在导入向导里把外部数据的列强制设为文本,导出侧则统一给危险前缀加单引号。

为什么 CSV 里的逗号没被识别成分隔符?

九成是文件里的逗号是全角的「,」,它不是 CSV 分隔符,会被原样留在字段里,于是整行挤成一列。用文本统计工具看一下首行的真实字符就能确认。另一个可能是导出用了分号或 Tab,这是欧洲 locale 的 Excel 默认行为。

字段里带换行、逗号、双引号,CSV 到底怎么写才算合法?

规则只有三条:含分隔符、换行或双引号的字段,整个用双引号包起来;字段内的双引号写成两个;行与行之间统一用一种行尾符。满足这三条,Excel、Python csv 模块和 SQL 导入都会解析出一致结果。

📂

松开以自动格式化

支持 .json / .sql / .csv / .html / .css / .xml / .yaml 文件