UTF-8 和 GBK 有什么区别:乱码的成因与修复
广告位(预留,AdSense 审核通过后启用)
打开一个 CSV,里面全是“鎴戝彨…”;网页上一片问号;老系统导出的文本在新电脑上变成“锟斤拷”。这些乱码有一个共同的根因:写入时用的字符编码,和读取时认为的字符编码不一致。理解了编码,乱码就不再神秘,多数情况都能自己修好。
一、先弄清几个名词
- 字符集:规定“有哪些字,每个字对应哪个编号”。Unicode 是涵盖全球文字的统一字符集。
- 编码:规定“编号怎么存成字节”。UTF-8、UTF-16 是 Unicode 的不同存法。
- GBK:针对中文的老编码,常用汉字占 2 个字节,在 Windows 中文环境里曾经非常普遍。
- GB 18030:我国的国家标准,兼容 GBK,并覆盖更多字符。其最新版本 GB 18030-2022 是强制性国家标准,2022 年 7 月发布,2023 年 8 月 1 日起实施,代替 2005 年版。具体条款以 国家标准全文公开系统 为准。
二、同一个词,字节完全不同
以“你好”为例:
UTF-8 : E4 BD A0 E5 A5 BD
GBK : C4 E3 BA C3
UTF-8 里一个常用汉字占 3 个字节,GBK 里占 2 个字节;英文字母和数字在两者里都是 1 个字节,并且数值相同,所以纯英文文本在两种编码下看起来都“正常”,这也是为什么乱码总是中文先出事。字节的差别意味着:同样的 6 个字节,换一种编码读,得到的字就完全不同。
三、三种典型乱码的“指纹”
- “浣犲ソ”这类生僻字:UTF-8 的内容被当成 GBK 读了。上面那 6 个 UTF-8 字节按 GBK 读,恰好是“浣犲ソ”。看到一堆莫名其妙的繁体和生僻字,多半是这种情况。
- 满屏 � 或问号:GBK 的内容被当成 UTF-8 读了。UTF-8 读不懂这些字节,会用替换字符 � 顶替。这种情况下信息已经被替换,通常不能再靠改编码还原,需要回到原文件重新打开。
- “锟斤拷”:已经被坏掉的内容又被保存过。它由 UTF-8 的替换字符再被当成 GBK 读出得来,意味着中间至少经过一次错误转换,原文很可能已经无法恢复。
四、修复乱码的步骤
- 先不要保存。很多编辑器一旦在乱码状态下保存,就把错误写进了文件。先另存一份备份。
- 换一种编码重新打开。记事本、VS Code 等编辑器都能在状态栏或“文件”菜单里选择“通过编码重新打开”,依次试试 UTF-8 和 GBK。
- 确认是否带 BOM。一些 Windows 程序用 UTF-8 的“带 BOM”格式,文件开头多出三个字节
EF BB BF。Excel 打开 CSV 时经常需要它才能正确识别 UTF-8,而一些程序会把它显示成开头的乱码字符。 - 转成统一的 UTF-8 再保存。确认显示正常后,另存为 UTF-8,今后协作统一用它。
- 命令行转换:Linux 上可以使用
iconv -f GBK -t UTF-8 in.txt > out.txt;先在小文件上验证,再批量处理。
五、网页和接口的乱码
- 网页要在 HTTP 响应头或 HTML 里声明字符集,例如
<meta charset="utf-8">,并保证文件本身真的是 UTF-8 保存的,两者必须一致。 - 接口、数据库、日志、前端页面,整条链路全部统一为 UTF-8,是避免乱码最省心的做法。
- 链接里的中文参数乱码时,先看是不是 URL 编码时用了 GBK,见 URL 编码一文,也可以用 URL 编码解码工具 切换 UTF-8 和 GBK 直接验证。
- 邮件或接口里的 Base64 内容解出来乱码,也要考虑是不是字符集不对,见 Base64 一文。
六、怎么判断一个文件到底是什么编码
- 看十六进制:用编辑器的十六进制视图看文件开头。出现
EF BB BF说明是带 BOM 的 UTF-8。 - 用命令:Linux 和 macOS 上
file -i 文件名能给出一个猜测的结果;注意它只是猜测,对很短的文件不一定准。 - 用试验:最可靠的办法还是依次用 UTF-8、GBK 打开,看哪个读起来通顺。短文本里有几个熟悉的汉字,就足以判断。
- 看来源:Windows 老软件导出的中文文本,往往是 GBK;网页、Linux 服务器、现代开发工具产生的文件,通常是 UTF-8。
七、新项目的选择建议
除非必须对接老系统,新项目一律选 UTF-8:它能表示全部 Unicode 字符、兼容英文的 1 字节写法、被浏览器和主流语言广泛支持。需要与老系统交换数据时,在边界处明确转换,并写进接口文档,不要让两种编码混在同一个文件里。
八、小结
遇到乱码,不要急着改内容:先判断是“谁写的、用什么编码”,再判断“谁读的、以为是什么编码”,两边对齐问题就解决了。养成统一使用 UTF-8、文件里标注编码、转换前先备份这三个习惯,就能避开绝大多数中文乱码。