大多数通用的压缩算法使用单字节粒度。
让我们考虑以下字符串:
"XXXXYYYYXXXXYYYY"
- 游程编码算法会说:“那4 'X',其次是4 'Y',其次是4 'X' ,然后是4'Y'“
- Lempel-Ziv算法会说:”这就是字符串'XXXXYYYY',后面是相同的字符串:所以让我们用第一个字符串替换第二个字符串。
- 霍夫曼编码算法会说:“该字符串中只有2个符号,所以每个符号只能使用一个位。”
现在让我们在Base64中编码我们的字符串。下面是我们得到:
"WFhYWFlZWVlYWFhYWVlZWQ=="
所有算法现在说:“什么样的混乱的是什么?”。而且他们不太可能压缩该字符串。
作为提醒,Base64的基本上的工作原理是3个字节重新编码群在(0 ... 255)转换成4个字节组(0 ... 63):
Input bytes : aaaaaaaa bbbbbbbb cccccccc
6-bit repacking: 00aaaaaa 00aabbbb 00bbbbcc 00cccccc
每个输出字节然后被转换成可打印的ASCII字符。按照惯例,这些字符是(每10个字符这里有一个标记):
0 1 2 3 4 5 6
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/
举例来说,我们的例子中字符串等于十六进制将0x58一组三个字节开始(字符“X”的ASCII码) 。或二进制:01011000.让我们将Base64编码:
Input bytes : 0x58 0x58 0x58
As binary : 01011000 01011000 01011000
6-bit repacking : 00010110 00000101 00100001 00011000
As decimal : 22 5 33 24
Base64 characters: 'W' 'F' 'h' 'Y'
Output bytes : 0x57 0x46 0x68 0x59
基本上,模式“3倍的字节将0x58”,这是明显的原始数据流中不是很明显了编码数据流中,因为我们将这些字节分成6位数据包并将它们映射到现在看起来是随机的新字节。
或换句话说:我们打破了大多数压缩算法所依赖的原始字节对齐方式。
无论使用什么压缩方法,它通常会严重影响算法的性能。这就是为什么你应该总是先压缩然后再编码。
这对于加密更加真实:先压缩,再加密。
编辑 - 约LZMA
笔记用作MSalters注意到,LZMA - 这XZ使用 - 正在比特流,而不是字节流。
不过,这种算法也将Base64编码遭受的方式是与我早先的描述基本一致:
Input bytes : 0x58 0x58 0x58
As binary : 01011000 01011000 01011000
(see above for the details of Base64 encoding)
Output bytes : 0x57 0x46 0x68 0x59
As binary : 01010111 01000110 01101000 01011001
即使是在比特级别的工作,它更容易识别的模式输入二进制序列比输出二进制序列。
“_base64-then-compress_明显地比_compress-then-base64_更糟且更慢” - 更不用说二者适用于所有意图和目的无关。 – MSalters