为什么base64编码要用=做对齐

首先明确一下问题,重点在“为什么做对齐”,而不是“为什么用=这个符号”。

先解释一下对齐操作。

base64编码的输入是字节串,每个字节8比特;输出是64进制串的文本,每个单元为6比特。如果输入长度是3的倍数,那么输出是不需要对齐的:

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/0 0 0 1 1 1 1 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 0/0 1 1 1 1 1

3个字节恰好被拆成了4个base64码。

但是如果输入长度不是3的倍数,那么就需要特殊处理了:

1、剩余长度为2字节

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 0/=

一是将第三个base64码的后两个比特填充0。另外,base64编码再最后对齐一个=等号,作为一个特殊的base64字符,表示空。

2、剩余长度为1字节

0 1 1 0 1 0 1 1
0 1 1 0 1 0/1 1 0 0 0 0/=/=

和前者类似,但是会对齐两个=等号。

经过等号对齐后,base64编码的长度就始终为4的倍数了。

但是,从编码解码原理上看,不对齐=也是没问题的,也不会造成二义性:

将base64编码视为每4个一组,

1)当最后一组长度为3时,说明是2个字节

2)当最后一组长度为2时,说明是1个字节

3)当最后一组长度为1时,不合法

解码时根据情况舍弃后面填充的0,转换为原字节,这个方案是完全没问题的。

那既然不对齐=也能正常工作,为什么要对齐呢?

我在https://stackoverflow.com/questions/4080988/why-does-base64-encoding-require-padding-if-the-input-length-is-not-divisible-by找到一个合理的解释。

考虑两个base64串的拼接:

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 0

+

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/0 0 0 1 1 1 1 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 0/0 1 1 1 1 1

如果对齐=,那么两个base64编码可以直接拼起来:

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/               /0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/0 1 0 0 1 1 1 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 0/=          /0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 1/0 0 1 1 1 1

解码时遇到=就知道那里没数据,做些特殊处理直接跳过。

而如果没有=对齐,就很麻烦了:

0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/0 1 1 0 1 0 1 1/1 0 0 0 0 1 0 1/0 1 0 0 1 1 1 1
0 1 1 0 1 0/1 1 1 0 0 0/0 1 0 1 0 1/1 0 1 0 1 1/1 0 0 0 0 1/0 1 0 1 0 0/1 1 1 1 0 0

注意标红的比特,左串的最后一个base64码,和右串的所有base64码都需要被改写!

因此,对齐机制至少有支持拼接这一好处,即使会稍微浪费一点空间。

posted @ 2020-09-10 14:27  Xrst  阅读(657)  评论(0编辑  收藏  举报