怎么判断一个文件是什么编码:BOM、自动识别的原理,以及 CSV 给 Excel 加 BOM 的正确姿势

· 约 4 分钟 🆎 文件编码转换

「这个文件到底是什么编码」是个比看起来难得多的问题——因为纯文本文件里根本没存这个信息。图片有魔数、压缩包有文件头(参见文件魔数速查),而 .txt / .csv / .log 从第一个字节到最后一个字节全是正文。编码是写入那一刻的约定,约定本身不随文件走。

所以判断编码只有两条路:碰上 BOM 这个例外,或者猜。

BOM:唯一的确定性线索

BOM(Byte Order Mark)是写在文件最开头的编码签名:

开头字节编码
EF BB BFUTF-8
FF FEUTF-16 LE
FE FFUTF-16 BE

它的本职工作是给 UTF-16 标字节序——FF FEFE FF 用来区分高低位哪个在前。UTF-8 没有字节序问题,所以 UTF-8 的 BOM 纯粹是一句「我是 UTF-8」的自我声明。

麻烦在于生态对这三个字节的态度完全分裂:

  • Windows 系依赖它。记事本、Excel 看到 EF BB BF 才确信是 UTF-8,否则按本地 ANSI 代码页(简体中文系统即 GBK)解码。
  • Unix 系当它是脏数据。shell 脚本开头有 BOM 会让 #! 不再位于文件第一个字节,直接执行失败;cat 拼接多个带 BOM 的文件,BOM 会混进正文中间;不少解析器把它当成正文开头一个看不见的字符(U+FEFF),字符串比对、按名取列悄悄失败。

所以「要不要 BOM」没有全局正确答案,取决于文件交给谁——这正是 CSV 问题的核心。

Excel 打开 UTF-8 CSV 乱码的完整逻辑

症状:程序导出的 CSV 明明是标准 UTF-8,Excel 双击打开满屏「娴嬭瘯鏁版嵁」。

原因:Excel 双击打开无 BOM 的 CSV 时不做编码猜测,直接按系统 ANSI 代码页解码。简体中文 Windows 的代码页是 936(GBK),UTF-8 字节按 GBK 双字节切分,就得到上面那种乱码——机制和浣犲ソ型乱码完全同源。

三种解法,按推荐度排:

  1. 加 UTF-8 BOM。Excel 认到签名就按 UTF-8 读。一次转换永久生效,收件人零操作——发给非技术同事的 CSV 一律用这个。
  2. Excel 里走「数据 → 从文本/CSV」导入,手动指定 65001: UTF-8。不改文件,但每次打开都要重新点一遍。
  3. 整个文件转成 GBK。适合对接只认 GBK 的老系统,代价是 GBK 装不下 emoji 和部分生僻字——转换时注意工具的丢字提示。

反方向的坑同样存在:带 BOM 的 CSV 交给数据管道(Hive 建表、自写脚本按行 split、部分库的默认参数)时,表头第一列会带上看不见的 U+FEFF,row['id'] 取不到值且报错信息毫无提示。给 Excel 的加 BOM,给程序的去 BOM,两个版本各存一份最省心。

没有 BOM 时,自动识别靠什么

两层手段,可靠性天差地别。

第一层:UTF-8 结构校验,近乎确定。 UTF-8 的多字节序列有严格语法——首字节 110xxxxx 后面必须跟且只跟一个 10xxxxxx1110xxxx 后面必须跟两个,以此类推。全文扫描一遍就知道是否合法。一段非平凡长度的文本「碰巧」满足这套语法的概率低到可以忽略,所以试解 UTF-8 成功 ≈ 确认是 UTF-8。这也是「拿不准先按 UTF-8 试」的依据。

第二层:双字节编码之间的统计推断,只能猜。 GBK、Big5、Shift_JIS 的双字节范围大量重叠,同一串字节在三种编码下往往都「合法」,只是解出来的字不同。chardet 这类库的做法是比较哪种解码结果更像真实语言——高频字命中率、字符共现概率——输出的是置信度,不是答案。

猜错的高发场景值得记住:

  • 文本太短。几十字节的样本统计不显著,这是自动识别翻车的头号原因——判断短文件时尽量找同来源的长文件一起看。
  • 简繁混排、中日混排,频率特征互相污染。
  • 内容本身偏离日常语言:人名地名清单、生僻字文档。

所以任何识别结果都要以预览为准:看到成段通顺的文字才算确认,置信度 99% 但预览是怪字,就是猜错了。

GB2312 / GBK / GB18030:一条直线上的三代

经常被当成三种编码,其实是严格向后兼容的三代国标:

标准年代规模备注
GB231219806763 字「镕」「堃」等字缺失
GBK199521003 字Windows 代码页 936 的实体
GB180302000全 Unicode现行强制标准,四字节变长

同一份字节按三个名字解码结果几乎一样——用 GBK 解 GB2312 文件永远正确,反过来可能缺字。所以工具识别报 GB2312 还是 GBK 不必纠结,输出时选 GBK 或 GB18030 总是安全的

至于新建文件:一律 UTF-8。只有对接明确要求 GBK 的老系统(银行对账单、政务导入模板、老 ERP)时才做转换,这正是文件编码转换的主场——拖入文件自动识别原编码,选目标编码即转,CSV 可勾选加/去 BOM,全程本地处理不上传。已经乱掉的文本则走乱码修复,原理见四类乱码的产生机制与可逆性判断

❓ 常见问题

文件里不是存着编码信息吗?为什么还要「猜」?

纯文本文件没有任何元数据,从头到尾只有正文的字节对比:图片有魔数(PNG 开头固定 89 50 4E 47)、压缩包有文件头,但 .txt / .csv / .log 什么标记都没有——编码是写入时的约定,不随文件走。所以:(1) 「这个文件是什么编码」严格说是无解的,只能根据字节的分布特征推断;(2) 唯一的例外是 BOM——文件开头的几个特征字节能确定性地标出 UTF-8/16/32;(3) 没有 BOM 时,所有「自动识别」本质都是统计学猜测。实务:拿不准时先按 UTF-8 试——UTF-8 的字节结构有严格语法,一段非平凡的文本「碰巧」是合法 UTF-8 的概率极低,试解成功基本就能确认。

BOM 到底是什么?就三个字节为什么这么多争议?

BOM(Byte Order Mark)是写在文件最前面的编码签名:UTF-8 是 EF BB BF,UTF-16 LE 是 FF FE,UTF-16 BE 是 FE FF它的本职是给 UTF-16 标字节序(FF FE 和 FE FF 区分高低位在前),UTF-8 没有字节序问题,加 BOM 纯粹当「我是 UTF-8」的签名用。争议在于生态分裂:(1) Windows 系(记事本、Excel)依赖它——没有 BOM 就按本地 ANSI 代码页猜;(2) Unix 系普遍当它是脏数据——shell 脚本首行有 BOM 会导致 #! 失效,cat 拼接文件会把 BOM 混进正文中间,不少解析器把它读成正文开头的多余字符(U+FEFF)。结论:BOM 不是编码的一部分,是给特定软件看的暗号——该不该加,取决于文件要交给谁

UTF-8 的 CSV 用 Excel 打开是乱码,为什么?怎么解决?

因为 Excel 双击打开无 BOM 的 CSV 时不猜 UTF-8,直接按系统 ANSI 代码页(简体中文环境即 GBK/GB18030)解码。UTF-8 的中文字节按 GBK 读,就是满屏「娴嬭瘯」式乱码。三种解法:(1) 给文件加上 UTF-8 BOM(推荐)——Excel 认到 EF BB BF 签名就按 UTF-8 读,一劳永逸,程序导出时写 CSV 用「UTF-8 with BOM」即可;(2) 用 Excel 的「数据 → 从文本/CSV 导入」手动指定编码——每次都要点,适合临时看一眼;(3) 把整个文件转成 GBK——中文环境的老系统对接时用,但 GBK 装不下 emoji 和部分生僻字,会丢字。注意反方向:加了 BOM 的 CSV 交给某些数据管道(Hive、老版本 pandas 默认参数、自己写的按行 split 脚本)时,第一列的表头会莫名多出一个看不见的 U+FEFF,按名取列取不到——两边的需求是冲突的,按下游是谁来定。

没有 BOM 时,「自动识别编码」是怎么做到的?可靠吗?

两层手段:先做结构校验,再做统计推断结构校验:UTF-8 的多字节序列有严格语法(首字节 110xxxxx 后必须跟且只跟一个 10xxxxxx,以此类推),全文扫一遍就知道是不是合法 UTF-8,这一步近乎确定。统计推断:GBK、Big5、Shift_JIS 都是双字节编码且字节范围大量重叠,同一串字节往往在三种编码下都「合法」,只能比较哪种解码结果更像真实语言——统计高频字命中率、字符共现概率,chardet 这类库给出的是置信度而不是答案。什么时候会猜错:(1) 文本太短——几十个字节的样本统计不显著,这是自动识别翻车的第一原因;(2) 简繁混排、中日混排;(3) 内容本身是罕见字组合(人名地名列表、生僻字文档)。实务:识别结果要和预览对照确认,看到成段通顺的文字才算数,不能只信置信度数字。

GB2312、GBK、GB18030 是什么关系?保存中文该选哪个?

三代国标,严格向后兼容:GB2312 ⊂ GBK ⊂ GB18030分别是:(1) GB2312(1980)收 6763 个常用简体字,「镕」「堃」这类字都没有;(2) GBK(1995)扩到 21003 字,补了繁体和部分生僻字,Windows 简体中文的代码页 936 实际就是它;(3) GB18030(2000,现行强制标准)四字节变长,理论覆盖全部 Unicode,emoji 也装得下。同一份字节,标成哪个名字解码结果几乎一样(GBK 解 GB2312 文件永远正确,反之可能缺字)。保存该选哪个:新文件一律 UTF-8——它是当下事实标准,跨平台无歧义;只有对接明确要求 GBK 的老系统(银行、政务、老 ERP 的导入接口)时才转 GBK/GB18030,且转换前要确认文本里没有 GBK 装不下的字符,转换工具会提示丢字风险。

🆎 打开 文件编码转换 GBK↔UTF-8 互转·自动识别原编码·CSV 加 BOM 让 Excel 不乱码·乱码文本一键还原·批量·本地处理不上传

📖 同一工具的其他教程

🔗 相关阅读

全部教程 →