文本文件与字符编码

             

1. 文本文件

   我们这里讨论的是文本文件(text file),也就是 Windows 中为人熟知的 txt 拓展名文件.文本文件只能储存字符,也就是说文件中的信息只能是 “有几个字符” 以及 “每个字符是什么”.所以文本文件本质上不包括字体,字号,下划线等等的其他信息.一个文件是否是文本文件是由它的储存格式决定的,而不是由拓展名决定的.一些其他的文件拓展名如 html,xml,md,以及大部分编程语言的代码文件都是文本文件.

   我们把所有非文本文件统称为二进制文件(binary file),因为从原理上来说任何文件都是以二进制的形式储存的.例如 Word 文档保存的 doc 或 docx 拓展名文件就是二进制文件,因为里面用其特定的格式储存了许多其他信息. 又例如图片文件 jpg, png,视频文件 mp4 等也都是二进制文件.

   文本文件的一个基本的问题是,字符以什么形式保存?从概念上来说,文本文件中每个字符对应一个整数,我们把对应的规则叫做编码(encoding),一个文本文件一般只使用一种编码.例如在著名的 ASCII(读作 asky)编码中,128 个字符被一一对应到 0-127 的整数1,这些字符包括大写和小写字母,数字,常见标点,以及一些格式上的符号如空格,换行符,制表符等.ASCII 编码可以满足通常的英语写作需求,但显然不支持其他语言如中文.下文会看到中文的文本文档通常以 UTF-8(Unicode 的一种)或者 GBK 编码储存.

   遗憾的是,一般情况下文本文档中不会声明使用的编码,所以如果储存和打开文件的默认编码方式不一致,就会导致显示乱码.尽管现在大部分系统和软件都用 Unicode 编码保存和打开文本文件,但仍然有一些软件为了兼容性使用以前的编码,例如 Windows 写字板(Notepad,不建议使用)默认将中文保存为 GBK(即中文环境下所谓的 ANSI)编码.

   如果经常编辑文本文档(尤其是编程),我们推荐使用一款功能较完善的编辑器,例如 Visual Studio Code(简称 VScode)2,Notepad++ 等.这里我们使用 VScode 编辑器为例进行介绍.

   当 VScode 打开一个文本文档时,会尝试自动检测编码,并显示在右下角的状态栏图 1

图
图 1:VScode 的右下角状态栏显示 Tab 的显示尺寸为 4 个空格,编码为 UTF-8,换行符为 LF,文件为普通文本文档

   如果这时编辑器中仍然显示乱码,说明自动检测失败,可以尝试手动切换不同编码打开文件:点击状态栏上显示的编码,选择 “Reopen with Encoding”,选择需要的编码即可.以正确的编码打开后,如果想改为别的编码,就选 “Save with Encoding”.

2. 换行符

   除了编码外,文本文件的换行符使用也有不同的规范.历史上,人们在使用机械打字机时,当一行打完,打字头停留在页面某一行的最右端.回车键(carrage return,简写为 CR)用于将打字头移动到页面的最左端,而 LF(line feed)键用于将纸张上移一行.在 ASCII 编码中,CR 和 LF 分别对应 13 和 10.Windows 系统沿用了这个传统,所以当我们在写字板程序中按下回车时,分别会在文件中插入 CR 和 LF 两个字符.Linux 系统默认使用单个 LF 换行,而 MacOS 则默认用单个 CR 换行.所以同一个文件在不同系统的默认编辑器中可能会出现全部文字排成一行的情况.一般来说,同一个文本文件应该使用同一个规范.

   无论在哪个系统中使用 VScode,它在打开文本文件时都会自动检测换行符并显示在图 1 的状态栏中3.若要将改变换行符,点击当前显示的换行符并选择即可.

3. ASCII 编码

   (表格未完成)

   其他绝大部分编码(如 Unicode,GBK)的前 128 个数字代表的字符都与 ASCII 相同,所以一个 ASCII 编码的文件用任何编码方式打开的结果都极有可能是相同的.

4. Unicode 编码

   Unicode 编码可以同时支持许多(人类)语言的字符,还包含一些图形(如箭头,多边形,数学符号等等)和 emoji 表情.它将每个字符和 0-4294967295(即 $2^{32}-1$)范围的整数一一对应.Unicode 分为几种不同的具体编码,UTF-32 是定长度的,即将每个字符都储存为 4 个字节(32 比特).最常见的 UTF-8 是变长度的,即如果字符对应的数字较小,就储存为 1 个字节(8 比特),随着数字变大,可以最多储存为 4 个字节.UTF-16 也是变长度的,原理和 UTF-8 类似,但一个字符最少对应两个字节.

   如今 UTF-8 是使用最广泛的文本文档编码,我们推荐尽可能使用 UTF-8 储存文本文档4.由于 UTF-8 最开始的部分是 ASCII 编码,所以如果文件中只含有 ASCII 字符,文件大小和 ASCII 编码的文件是一样的.

Byte Order Mark

   在 Unicode 编码的文件开头(很少用于 UTF-32),有一些软件会插入(或需要)2 到 3 个字节的 BOM(byte order mark),这样一是可以表明文件使用 Unicode 编码,二来可以表明字节排列顺序.当一个整数需要用多个字节表示时,不同的系统可能会把这些字节倒置,即所谓的 big endian 和 small endian.

   VScode 同样可以自动检测文件是否存在 BOM,如果有则显示在状态栏的编码中,例如 “UTF-8 with BOM”.


1. ^ 另外有 extended ASCII 编码对应 0-255 的整数
2. ^ 注意 Visual Studio Code 不是 Visual Studio,是一款轻量级文本编辑器,可以通过安装插件拓展许多功能.
3. ^ 一般不会检测失败,除非不同的换行符格式混用
4. ^ 本书介绍的 Matlab 编程语言,从 R2020a 版本开始默认使用 UTF-8 储存代码文件,在此之前中文系统的代码文件默认以 GBK 储存.而大部分编程语言很早以前就使用 UTF-8 编码了.

致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择会员制,大量广告,内容付费等。 因此,我们请求广大读者热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 10 元,我们一个星期内就能脱离亏损, 并保证网站能在接下来的一整年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。

         

© 小时科技 保留一切权利