乱码折腾记:从 GBK 到 UTF-8

  • 建站笔记

前阵子整理网站,我把一批从网上存下来的说明文件和几份老笔记放到页面上。这些文件在我电脑上双击打开,字是字、行是行,中文一句不差。传上去一刷新,全变成一堆问号和怪符号,中间还夹着几个小方块。

现象:本机看着好好的,放到网页上就花了

我第一反应是文件坏了。重新下载一遍,还是这样。同事过来看一眼,说要不换个地方下;我换台电脑打开,又正常了。当时我确实有点懵:同一份文件,怎么换个地方打开就是两个样子。

那天下午我干的事挺没技术含量的:把文件原样复制一份,字节数数过,一模一样;大小也一样。文件明明是同一份,只是“看它的地方”换了。折腾了半天才明白,文件一个字节都没坏,坏的是我“怎么读它”这件事。

讲人话:文件自己不写明是什么编码

把话说白一点。一个文本文件,说到底就是硬盘上一串字节,每个字节是一个 0 到 255 之间的数字。这些数字本身没有意义,得有人给它们一套规则,说“这几个数字凑在一起算一个汉字”,它才变成能读的中文。

麻烦就麻烦在,文件里通常不写“我用的是哪套规则”。它就是一堆数字,安安静静躺在那儿,谁去读它,谁自己想办法。

本地编辑器愿意想办法。它一般按系统默认的那套规则去猜,我们办公室的电脑是中文 Windows,默认那套正好就是大多数中文老文件用的那套,所以一猜一个准,看着当然正常。

浏览器不一样,它基本不猜。

浏览器拿到一个没有声明编码的文本文件,默认就按 UTF-8 解释,猜都不猜。

同样是那串字节,编辑器用的是 A 规则,浏览器用的是 B 规则,读出来的东西当然不一样。这就是“本机好好的,一上网就花”的全部原因。

为什么偏偏是中文老文件踩这个坑

因为中文 Windows 上默认那套规则是 GBK。十几年前从网上下载的说明文件、字幕文件,还有别人发过来的老笔记,绝大多数都是 GBK 存下来的。那时候大家也没得选,系统是什么就用什么。

而这些字节在 UTF-8 里,很多组合压根不是一个合法字符。浏览器按 UTF-8 往下读,读到一半发现“这不对啊”,只能给你一个问号或者一个替换符号。一整篇中文读下来,就是满屏问号。这跟文件好坏没关系,纯粹是规则对不上。

怎么确认:换个编码打开就知道了

不用背理论,我就用一个笨办法判断。同一份文件,用编辑器打开,另存的时候把编码从 UTF-8 换成 GBK(或者反过来),再打开看一眼:

我平时还会拿“能不能严格按 UTF-8 解出来”当第一道筛子。严格模式下解不出来会直接报错,而不是硬塞一堆问号给你,报错反而是好事,说明它老实。

怎么修:三层,从外到内

第一层最干脆:把文件本身转成 UTF-8。这一步做了,以后谁来读都是对的,属于根治。单份文件很好办,用编辑器打开,另存为的时候把编码选成 UTF-8(不带 BOM 的那种),保存完再看一眼内容有没有变样,没变就对了。我现在收进来的文本,基本都是这么过一道再往网站上放。

第二层是读的时候做兜底。万一漏了一个没转的,那就别只按一种规则硬读——先按 UTF-8 解,失败了再依次试 GBK、Big5 这些。浏览器里可以用 TextDecoder 干这件事,给它一个严格模式,解不出来就抛错,抛错就换下一种,一路试下去:

const list = ['utf-8', 'gb18030', 'big5', 'euc-kr'];
for (const enc of list) {
  try {
    return new TextDecoder(enc, { fatal: true }).decode(bytes);
  } catch (e) { /* 这种不行,换下一种 */ }
}

注意 { fatal: true } 是关键。不写它,TextDecoder 碰到解不了的字节不会报错,而是塞一堆问号进去,看着“成功”了,其实还是乱的。

第三层是批量收拾历史文件。这种活手动点不完,写个脚本扫一遍目录,逐个认编码、逐个转,转之前先备份一份。有备份在手,出问题还能退回去,心里踏实。

我现在习惯让脚本分两步走:先不带参数跑一遍,只体检、只列清单,告诉我哪个文件是什么编码、打算怎么处理,一个都不动;清单看下来没问题,再带上“真转”的参数跑第二遍。多花两分钟看一眼,比转完一整个目录再回头找哪里坏了要省事得多。转完我还会随手抽两三个文件打开确认一下,尤其是那种原来就带问号的,转完还是问号,那就不是编码的事,是原来那份文件下下来就已经缺字了。

两个反直觉的坑

第一个坑:能解码成功,不等于编码对了。有段时间我以为“能解开就是对的”,结果被打脸。GBK 和 EUC-KR 这两种编码,字节范围是有重叠的。一份中文文件,你拿韩文那套规则去解,它也能“成功”解出东西来,一个错都不报——只不过解出来全是假韩文,一个中文字都找不着。

所以判断编码,不能只看能不能解成功。得看解出来的内容里各类文字各占多少:中文文件解出来就该大部分是汉字,日文的该有假名,韩文的该有谚文。按这个打个分,再结合文件名里的线索一起判断,才靠谱得多。

第二个坑:同一份文件,换个目录,编码可能就不一样了。同一批资料我在两个目录里各放了一份,其中一个目录以前整理过、转过编码,另一个忘了动。结果同名文件、同样的内容,一个目录里是 UTF-8,另一个目录里还是 GBK。我一开始按文件名去修,以为修过一个就完事,另一个目录那份照样乱。后来改成按目录分别扫,一个目录一个目录地过,才算干净。

编码这事看着挺玄,名词一堆,其实就一句话——字节没问题,是读的规则不对。下次再碰上乱码,先别急着骂文件坏了,想清楚两件事:谁在读它,它按什么规则读。这两句想明白了,问题就清楚一半,剩下的无非是转一次、备份一次、再多扫一遍目录。


本文写于 2026-09-11,记录的是当时的情况与做法,未必适用于所有环境,仅供参考。

← 返回文章列表