📄 一句话概括
文件在磁盘上就是一串字节,一个字节 8 位;所谓【文字】只是这些字节按某种编码解读出来的结果——压缩就是让字节数变少。
📝 本节和前面几节的关系
第五章讲的是数据放在哪儿,这一章开始动它:把数据变小。
一、文件到底是什么
在磁盘上,文件就是一串字节,一个字节 8 位。 没有所谓的【文字文件】和【图片文件】之分——在存储层面它们是同一种东西。 差别只在你怎么解读这串字节:按 UTF-8 读出来是文字,按像素读出来是图像。 所以【压缩】这件事有非常准确的度量:看字节数少了多少。
二、文字只是一个编码的说法
同一句话,写成字节之后长这样:英文字母 1 字节、汉字 3 字节(UTF-8 下)。 标点、空格、换行,全都是实实在在的数据,一样占字节。 换个编码,字节数还会变——同一段文字在 UTF-8 和 GBK 下就不一样长。 所以压缩的第一件事是面对字节,而不是面对【字】。
三、压缩怎么度量
两个数就够了:压缩前后各多少字节,比值是多少。 压到一半叫 50%,也叫 2 倍压缩;说清楚用的是哪种说法,免得误会。 还有一条底线要记住:无损压缩的还原必须一个字节都不差。 只要允许差一点,压缩空间就会大得多——这就是无损与有损的分水岭。
四、这一章要走的四步
先看最简单的规律——连续重复,对应游程编码(6.2、6.3)。 再看更通用的规律——出现频率,对应哈夫曼(6.4 到 6.6)。 最后把两类压缩分清——无损与有损(6.7)。 这一章的名字叫【自己动手】,所以每一步都会有能跑的小程序把账算给你看。
五、动手 Demo:文件是以字节为单位记录的
文件在磁盘上就是一串字节,一个字节 8 位。 文本文件也不例外——文字只是字节按编码解读出来的结果。
s = "Hello, 世界"
raw = s.encode("utf-8")
print("字节数 %d" % len(raw))
print("十六进制 %s" % raw.hex(" "))
for ch in s:
print("%s -> %s" % (ch, ch.encode("utf-8").hex(" ")))
实跑输出:
--------------------------------------------------------------------
文件是以字节为单位记录的
--------------------------------------------------------------------
**文件在磁盘上就是一串字节,一个字节 8 位。**
文本文件也不例外——所谓【文字】,只是这些字节按某种编码解读出来的结果。
原字符串 Hello, 世界
字节数 13
十六进制 48 65 6c 6c 6f 2c 20 e4 b8 96 e7 95 8c
字符 编码方式 占几字节
-------------------------------
H 48 1
e 65 1
l 6c 1
l 6c 1
o 6f 1
, 2c 1
20 1
世 e4 b8 96 3
界 e7 95 8c 3
三件事一下就清楚了:
**英文字母只要 1 字节,汉字要 3 字节**(UTF-8 下)
**空格也是数据,实实在在占着 1 个字节**
**同一段文字换个编码,占的字节数就会变**
所以【压缩】这件事有准确的度量:**看字节数少了多少。**
英文字母 1 字节、汉字 3 字节,空格也实实在在占着 1 个字节。 压缩面对的是字节数,不是【字数】。
30 秒实验
- 把你的名字按 UTF-8 编码,数一数占几个字节。
- 找一个 txt 文件,看看它的大小和里面字符的个数差多少。
常见误区
- 以为文字文件里存的是【文字】。里面就是字节,文字是解读出来的。
- 以为压缩比只有一种说法。压到 50% 和 2 倍压缩是一回事,说清楚单位。
自测三问(点开对答案)
1. 文件在磁盘上到底存的是什么? —— 一串字节(一个字节 8 位);所谓文字、图像都是按某种规则解读这些字节的结果。 2. UTF-8 下英文和汉字各占几字节? —— 英文字母 1 字节,汉字通常 3 字节。 3. 无损压缩的底线是什么? —— 压缩后必须能一个字节都不差地还原回来。- ☐ 下一节(6.2 游程编码的原理)
相关笔记
- 游程编码的原理 — 从最简单的规律开始
- 无损压缩与有损压缩 — 先把底线划清
- 了解一下磁盘的物理结构 — 这些字节最后躺在哪儿
- 🔵 计算机基础 · 索引 — 硬件底层的入门课
- ⚙️ 程序是怎样跑起来的 · 索引