![深入理解序列化与反序列化](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=1739300377-REfrdijSK55FhbsDeKeg1DK3jsy2KjEZ-0-46f3089c62dd0d1363b1431a45e8d6da)
索引表的最后两个索引默认是+和/字符;在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=1739300377-yxRzmj4h5HFcZfUC9Jgb4MjZNWuwwOfO-0-fb7cd3ed43211b080e3d04e95b2d960f)
续表
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_15.jpg?sign=1739300377-BF6LALSSKt9dvAIZyKVoyfCfKNmJ0IgG-0-8471e56b31a4f822af59d4d38000ee58)
· 编码示例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=1739300377-DNreecIDlpVrwY8eHHImYQ4k7Tm613Hg-0-664deb03580a3b24c4e53586b597fe7d)
· 解码示例:Base64编码值为abI
表1-8给出了Base64的解码过程。
表1-8 Base64的解码过程
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_17.jpg?sign=1739300377-GUNfIgtnVSWLr6R8ARC7ET0WQEoyA2jd-0-df1e0d4756510910eeee41efecc8912d)
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=1739300377-grE6c6fJtqBPDuVe6jJN11eSoIQb8dyO-0-fd98ef184e96d157ea730ff80bcc2714)
代码注释中的数字表示编码后的字节数,读者可自行验证。
· commons-codec
![img](https://epubservercos.yuewen.com/171F30/18519308908425106/epubprivate/OEBPS/Images/txt002_19.jpg?sign=1739300377-i5TduSqF1rnyLl8ttD4h9x0sk0LX2QGW-0-3bce59cf6c4aea549443e56cfaff2ec0)
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=1739300377-Fop6lDfdWCXsINs3mSWZnyDymkPPvLba-0-66701eea2cf81f4a61df55d12c68e9de)
值得一提的是,JDK很早就提供了sun.misc包下的BASE64Encoder和BASE64Decoder,能满足Base64编码和解码的需求。但因为运行性能差,没有被开发人员广泛使用,这里不展开讨论。