![深入理解序列化与反序列化](https://wfqqreader-1252317822.image.myqcloud.com/cover/521/34667521/b_34667521.jpg)
1.3 Base64编码
在数据传输的场景中,如果都是英文字符,传输能正常进行;但如果出现非英文字符,如中文字符、日文字符、不可打印字符、多媒体文件等,则可能出现乱码。为了解决上述问题,Base64编码方案被提出。Base64编码基于8 bit分割,以可打印字符为最终体现形式完成对数据的编码。
1.3.1 编码规则
1)对原始数据按6 bit进行分割;如果当前所有bit长度不是6的整数倍,则有剩余bit。
2)对6 bit进行高位补齐2个0,凑成8 bit;在剩余bit前面补齐若干个0,凑成8 bit。
3)补齐后的每个字节称为索引,最大值为00111111(63),最小值为000000(0)。
4)根据索引表,将索引替换成目标字符。
1.3.2 解码规则
1)根据索引表,将字符替换成索引,每个索引为1个字节,对应8 bit。
2)将每个索引的前2个bit(值为00)去掉,剩余所有bit长度为N。
3)在小于等于N的范围内找到第一个最接近N且能被8整除的数M。
4)如果N和M相等,则说明编码之前的所有bit长度是6和8的公倍数,长度为N的所有bit按照8 bit切分即完成解码。
5)如果M<N,说明编码之前的所有bit长度不是6的整数倍,需要对长度为N的bit序列的最后一个6 bit块进行如下处理:去掉高位(N-M)个bit,剩余的M个bit按照8 bit切分即完成解码。
1.3.3 索引表
表1-5显示了完整的Base64索引表。
表1-5 Base64索引表
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_13.jpg?sign=1739279824-9QQDmcZtXFyWQUmpKiFPgiRiUT8l2Zwf-0-b503f2555851379f74f38a53ece2d0a5)
索引表的最后两个索引默认是+和/字符;在URL编码时,需要用-(横杠)和_(下画线)替代。
1.3.4 编码与解码示例
· 编码示例1:bit长度是6的整数倍
表1-6给出了待编码数据的bit长度能被6整除情况下的编码过程。
表1-6 bit长度是6的整数倍
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_14.jpg?sign=1739279824-015iHZQ7PkS7bnE3mryJ8GTHKejCuqag-0-7a92037bc983637e94060bdf47969366)
续表
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_15.jpg?sign=1739279824-roX6A5jnUIWktdCynNPDrCzdMh66tT2M-0-8ba719a51fc3b67880421f452e3f1e2c)
· 编码示例2:bit长度不是6的整数倍
表1-7给出了待编码数据的bit长度不能被6整除情况下的编码过程。
表1-7 bit长度不是6的整数倍
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_16.jpg?sign=1739279824-zv3qM2IMWCedlfM1qZnaHhvXfiCwNMMB-0-c3a5cf09b5ae21945dabb95adcc55e38)
· 解码示例:Base64编码值为abI
表1-8给出了Base64的解码过程。
表1-8 Base64的解码过程
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_17.jpg?sign=1739279824-eyp1TxEq20zu5TAYztH0b7TEIiY4eYNr-0-6122b4003b73128cb1b25cb23d0ed422)
1.3.5 Java应用示例
· Java 1.8 Base64
从Java 1.8开始,JDK包含了java.util.Base64,应用示例如下。
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_18.jpg?sign=1739279824-nOgAJGIrSw9AXC44j7h6L9ZIFXrAhixw-0-074f1515cc0644d115527743275aab29)
代码注释中的数字表示编码后的字节数,读者可自行验证。
· commons-codec
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_19.jpg?sign=1739279824-2zordfEzFJFTrbg12Nqn3JkUMUIaaUmm-0-2d4b9cb50752fbaa83bc5e472cfcd238)
commons-codec编码后的字节长度是8,这是因为内部实现默认使用了字节对齐的特性。
针对上述两种实现,笔者做了性能对比,Java 1.8的Base64实现更高效,对比数据如表1-9所示。
表1-9 Base64编码性能对比
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_20.jpg?sign=1739279824-FHwPGV6jIrxwFKYCqsLSGp0P67nnlN7x-0-cfe7f260c815813b60b95f496ff36909)
值得一提的是,JDK很早就提供了sun.misc包下的BASE64Encoder和BASE64Decoder,能满足Base64编码和解码的需求。但因为运行性能差,没有被开发人员广泛使用,这里不展开讨论。