文字、图片与文件格式

计算机存储的所有文件底层都是字节序列。同一个字节 0x41,按整数解释是 65,按英文字符解释是大写字母 A,在图像数据中则可能表示某个颜色通道的数值。具体含义取决于读取它的软件采用什么格式规则。

字符编码:ASCII、Unicode 与 UTF-8

要把文字存进计算机,就得先规定每个字符对应哪个数字编号,这叫字符编码:

  • ASCII:最早期的英文编码表,只占 1 个字节,规定了 0–127 共 128 个字符(英文大小写字母、数字、常见标点等)。比如大写字母 A 是 65(十六进制 0x41),字符 '5' 是 53(0x35)。
  • Unicode:为了装下全世界所有语言的文字和 Emoji,Unicode 给每个字符分配了一个统一的编号(叫码点),比如 A 是 U+0041,汉字 乌 是 U+4E4C。
  • UTF-8:现在最通用的存储方案,用来把 Unicode 编号存成实际的字节。它是变长编码:
    • 英文、数字和英文标点占 1 个字节(和 ASCII 一模一样);
    • 绝大多数常用汉字占 3 个字节;
    • 少数生僻字和 Emoji 占 4 个字节。
字符Unicode 码点UTF-8 字节(十六进制)占几个字节
AU+0041411 字节
乌U+4E4CE4 B9 8C3 字节

比如一个 UTF-8 文本文件里只写了 A乌 两个字,它在硬盘上存的字节就是 41 E4 B9 8C,一共占 4 个字节。

A 与乌分别对应一个和三个 UTF-8 字节

乱码与换行符

为什么有时候打开别人发的文本文件会看到一堆乱码?通常不是文件坏了,而是存文件时用的编码和打开时用的编码对不上(比如对方用老式 GBK 编码保存,每个汉字占 2 个字节;你的编辑器却按 UTF-8 每 3 个字节切一个字去读,自然就全乱了)。遇到乱码时千万别点保存,换个编码重新打开就行。

另外,平时按回车键换行,在文件里也是实打实占字节的:

  • Linux / macOS 用 LF(0x0A)表示换行,占 1 个字节;
  • Windows 用 CRLF(0x0D 0x0A)表示换行,占 2 个字节。

如果在 A乌 后面按了一下回车(按 Linux 的 LF 算,多了个 0A),整个文件的字节就会变成 41 E4 B9 8C 0A。

从字节记录计算大小

练习

一个文件的完整字节记录为:41 E4 B9 8C 0A。 每组两位十六进制表示一个字节,没有其他内容。这个文件共多少字节?只提交整数。

提交答案

题解 Hint

图片像素、文件头与扩展名

图片是由一个个小方格像素(Pixel)拼起来的。在常见的 RGB 模型里,每个像素的颜色由红(R)、绿(G)、蓝(B)三个通道混合而成,每个通道占 1 个字节(00 到 FF,即 0 到 255)。比如亮绿色 #A9DC76,拆开就是红 0xA9(169)、绿 0xDC(220)、蓝 0x76(118):

课程绿色由红 169、绿 220、蓝 118 三个分量组成

那软件怎么知道一个文件是 PNG 图片还是 ZIP 压缩包呢?很多文件格式会在开头几个字节写上固定的特征码,叫文件头签名或魔数(Magic Bytes)。比如 PNG 图片开头的 4 个字节固定是 89 50 4E 47。

而文件名后面的扩展名(比如 .jpg、.txt)只是给操作系统看的一个标签,用来决定双击时默认拿什么软件打开它。把 photo.jpg 改名叫 photo.txt,里面的图片字节一点都没变,用记事本硬打开只会看到乱码。后面学文件上传漏洞时就会看到,如果服务器只看文件名是不是 .jpg、不检查文件里面的真实内容,就很容易被攻击者上传伪装成图片的脚本。

注意

还要注意区分编码、压缩和加密:UTF-8 编码和 ZIP/PNG 压缩用的都是公开规则,谁拿到文件都能直接还原;只有加密才需要密钥,用来防止别人看到明文。