简介

我们知道计算机中的文件可以分为两种,一种是人肉眼可读的文本类文件,一种是肉眼不可读的二进制文件。一般来说二进制文件如果用文本编辑器打开的话会显示乱码,并且二进制文件和文本文件的存储和传输方式是不一样的,那么有没有什么办法将二进制文件转换成为文本文件进行传输或者存储呢?答案是肯定的。

这种编码方式就是我们今天要讲到的Base64编码。

Base64和它的编码原理

Base64是一种将二进制编码格式转换为text编码的一种形式。我们知道二进制编码是0和1的形式,它的单位通常是一个字节,也就是8bits,每个bit表示的是0或者1。

而文本编码的格式有很多种,最早也就是最简单的编码格式就是ASCII编码,ASCII编码的全称是American Standard Code for Information Interchange,也就是美国信息交换标准代码,它主要表示的是常用的一些西欧字符。

ASCII的编码范围是0x00-0x7F,用十进制来表示就是0-127,总共128个字符,刚好是7bits表示的范围。

ASCII编码中包含了33个控制字符和95个可打印的字符,如下所示:

ASCII码 含义ASCII码 含义
16进制10进制2进制 16进制10进制2进制
0x0000NUL 空0x40641000000@
0x0111SOH 标题开始0x41651000001A
0x02210STX 正文开始0x42661000010B
0x03311ETX 正文结束0x43671000011C
0x044100EOT 传输结束0x44681000100D
0x055101ENQ 询问字符0x45691000101E
0x066110ACK 承认0x46701000110F
0x077111BEL 报警0x47711000111G
0x0881000BS 退一格0x48721001000H
0x0991001HT 横向制表0x49731001001I
0x0A101010LF 换行0x4A741001010J
0x0B111011VT 垂直制表0x4B751001011K
0x0C121100FF 走纸控制0x4C761001100L
0x0D131101CR 回车0x4D771001101M
0x0E141110SO 移位输出0x4E781001110N
0x0F151111SI 移位输入0x4F791001111O
0x101610000DLE 数据链路转义0x50801010000P
0x111710001DC1 设备控制10x51811010001Q
0x121810010DC2 设备控制20x52821010010R
0x131910011DC3 设备控制30x53831010011S
0x142010100DC4 设备控制40x54841010100T
0x152110101NAK 否定0x55851010101U
0x162210110SYN 空转同步0x56861010110V
0x172310111ETB 信息组传送结束0x57871010111W
0x182411000CAN 作废0x58881011000X
0x192511001EM 纸尽0x59891011001Y
0x1A2611010SUB 换置0x5A901011010Z
0x1B2711011ESC 换码0x5B911011011[
0x1C2811100FS 文字分隔符0x5C921011100\
0x1D2911101GS 组分隔符0x5D931011101]
0x1E3011110RS 记录分隔符0x5E941011110^
0x1F3111111US 单元分隔符0x5F951011111_
0x2032100000(space)0x60961100000`
0x21331000010x61971100001a
0x22341000100x62981100010b
0x2335100011#0x63991100011c
0x2436100100$0x641001100100d
0x2537100101%0x651011100101e
0x2638100110&0x661021100110f
0x2739100111'0x671031100111g
0x2840101000(0x681041101000h
0x2941101001)0x691051101001i
0x2A42101010*0x6A1061101010j
0x2B43101011+0x6B1071101011k
0x2C44101100,0x6C1081101100l
0x2D45101101-0x6D1091101101m
0x2E46101110.0x6E1101101110n
0x2F47101111/0x6F1111101111o
0x304811000000x701121110000p
0x314911000110x711131110001q
0x325011001020x721141110010r
0x335111001130x731151110011s
0x345211010040x741161110100t
0x355311010150x751171110101u
365411011060x761181110110v
0x375511011170x771191110111w
0x385611100080x781201111000x
0x395711100190x791211111001y
0x3A58111010:0x7A1221111010z
0x3B59111011;0x7B1231111011{
0x3C60111100<0x7C1241111100\
0x3D61111101=0x7D1251111101}
0x3E62111110>0x7E1261111110~
0x3F63111111?0x7F1271111111DEL 删除

Base64就是从ASCII编码中挑选出64个字符和二进制一个字节8bits进行映射,这也就是Base64中64的含义。为什么要选择ASCII编码呢?这是因为ASCII编码是最早出现的编码形式,几乎所有的计算机应用都对其完全支持,不会出现数据传输过程中的内容转换,非常的安全。

当然Base64编码也有多种编码形式,比如在MIME中,Base64选择的是A-Z, a-z, 和 0-9 总共62个字符,再加上其他自选的两个字符组成了64个编码字符。

64个字符用二进制表示是6bits,而常用的二进制使用一个字节来表示,也就是8bits,那么问题来了,怎么将8bits的二进制用6bits的Base64字符来表示呢?

很简单,我们只需要将3个8bits连接起来,变成24bits,这样就可以用4个Base64来表示了。

为什么必须对二进制进行转换呢?这是因为互联网中的某些传输协议只支持某些特定的字符集,如果是其他的字符集是不支持的。比如说常用的发送电子邮件的附件。因为SMTP协议最开始设计的时候是支持7 位 ASCII 字符,所以如果要传输文件的话,我们需要对文件进行编码之后再进行传输。

另外Base64的一种用法就是在HTML中将图片嵌入到网页中,从而实现图片的展示。

虽然Base64很好用,但是因为其只能使用6bits的字符映射集,所以会造成数据映射的损失,从而导致二进制文件编码过后文件体积变大的缺点。

Base64的变体

Base64简单点说就是bit到bit之间的映射,那么肯定不止一种映射方式,我们来看下Base64编码方式的各种变体,通常来说前62位基本上是一样的,不同之处在后面两个字符,以及用于填充的字符(这在某些协议中可能是强制性的,或者在其他协议中可能被删除)。

下表是常见的Base64编码的变体:

编码名称编码字符编码字符编码字符
第62位第63位补全符
RFC 1421: Base64 for Privacy-Enhanced Mail (deprecated)+/= mandatory
RFC 2045: Base64 transfer encoding for MIME+/= mandatory
RFC 2152: Base64 for UTF-7+/No
RFC 3501: Base64 encoding for IMAP mailbox names+,No
RFC 4648: base64 (standard)+/= optional
RFC 4648: base64url (URL- and filename-safe standard)-_= optional
RFC 4880: Radix-64 for OpenPGP+/= mandatory

Base64的编码细节

上一节我们讲到了Base64编码的基本原则和一些常见的变体,那么到底是如何进行映射的呢?

本节我们会以Base64的标准形式RFC 4648为例来进行详细的讲解。

RFC 4648选择+和/这两个字符作为编码中的第62位和63位,并且选择=作为补全字符。

首先来观察一下RFC 4648的映射表:

索引二进制字符索引二进制Char索引二进制Char索引二进制Char
0000000A16010000Q32100000g48110000w
1000001B17010001R33100001h49110001x
2000010C18010010S34100010i50110010y
3000011D19010011T35100011j51110011z
4000100E20010100U36100100k521101000
5000101F21010101V37100101l531101011
6000110G22010110W38100110m541101102
7000111H23010111X39100111n551101113
8001000I24011000Y40101000o561110004
9001001J25011001Z41101001p571110015
10001010K26011010a42101010q581110106
11001011L27011011b43101011r591110117
12001100M28011100c44101100s601111008
13001101N29011101d45101101t611111019
14001110O30011110e46101110u62111110+
15001111P31011111f47101111v63111111/
补全符=

我们来以单词man为例,来观察一下Base64的编码流程。

man这个单词在ASCII中分别用77, 97和110表示,转换成为二进制就是01001101, 01100001 和 01101110。

将上面的三个二进制合并在一起就成了:010011010110000101101110, 总共24-bit,从上面的表中选择出对应的字符,所以我们可以得到man经过base64编码之后得到:TWFu。

上面的例子中,man刚好是3个字符,也就是24个bits,可以用base64完整的表示。如果我们只有ma这两个字符,应该怎么进行编码呢?

和上面一样,ma的二进制分别是01001101, 01100001,合并起来就是0100110101100001。

但是上面的bits只有16位,因为一个base64是6bits,所以可以用3个base64来表示,因为原始的bits少了两位,所以用0来补全:

0100110101100001+00 = 010011010110000100。

010011010110000100转换成为base64就是TWE,因为base64编码需要4个字符,所以最后的字符用=来补全,也就是说me经过base64之后变成TWE=。

总结

以上就是Base64的基本含义和转换规则,其实协议很简单,将要转换的数据变成二进制,然后对照转换表格进行转换和补全即可。

本文已收录于 http://www.flydean.com/18-base64-encoding/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!


flydean
890 声望433 粉丝

欢迎访问我的个人网站:www.flydean.com