阅读 109

我不知道的Base64

什么是Base64?

规范文档详见: RFC 2045

先来看一个网上的题目:

在网络传输数据时,经常需要将二进制数据转换为一个可打印字符串。一般用到的可打印字符集合包含64个字符,因此又称为Base64表示法。现有一个char数组长度为12,要将它表示为Base64字符串,请问Base64字符串最少需要____个char;如果char数组长度为20,则需要____个char。


  • 什么是Base64?
  • 为什么要有Base64?
  • 什么是可打印字符?
  • 什么是ASCII字符?

我们把问题从后往前看,先来看看什么是ASCII码。

一、ASCII

以下内容摘自[百度百科](baike.baidu.com/item/ASCII/…

ASCII ((American Standard Code for Information Interchange): 美国信息交换标准代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的信息交换标准,并等同于国际标准ISO/IEC 646。

它是一个标准,一个规定了计算系统中常用的一些字符的二进制值的标准。ASCII码表一共有128位,其对应的**ASCII码表**见后文。

  • **0~31及127(共33个)是控制字符或通信专用字符(其余为可显示字符),**如控制符:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)、BEL(响铃)等;通信专用字符:SOH(文头)、EOT(文尾)、ACK(确认)等;ASCII值为8、9、10 和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响[1] 。

  • 32~126(共95个)是字符(32是空格),其中48~57为0到9十个阿拉伯数字。

  • 65~90为26个大写英文字母,97~122号为26个小写英文字母,其余为一些标点符号、运算符号等。

所以,ASCII码表中32~126一共95个字符都是可打印的字符。也就是在网络中可以传输的字符。这就解决了什么是可打印字符的问题。

二、为什么要有Base64

熟悉web开发的人员大底都知道,HTTP报文是由一行一行的简单字符串组成的。HTTP报文都是纯文本,不是二进制代码。所以你也可能看到过关于说为什么HTTP协议传输不使用二进制,而使用文本进行传输的抱怨。

另外,我们通过HTTP传输数据,在HTTP1.1版本中是可以传递二进制数据的。那在HTTP0.9或者是只支持ASCII文本传输的协议中(SMTP/POP3),我们如何传输二进制流的数据呢?这就需要用到相应的转码方式来对二进制数据进行转码并传输。其中Base64就是一种。

三、什么是Base64

Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。可查看RFC2045~RFC2049,上面有MIME的详细规范。

Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息

参见Base64对照表,我们需要使用基本的64个字符来表示二进制数据,每个字符都有对应的索引,最大的索引值为63。63的二进制表示值为:00111111,可以用6个bit就能表示。所以如果我们使用这些字符的索引值的二进制来推导出一般的8bit二进制码,即可用来表示想要编码的值了。

转换规则:

  1. 把每3个8bit字节变成4个6bit字节。(想想为什么是3个8bit)
  2. 每76个字符加一个换行符。
  3. 最后的结束符也要处理。
  4. 不足3个8bit的数,使用0补位,并用"="来代替

这么说可能比较空泛,拿我名称的首字母缩写lsy做示例:

  • lsy的ASCII码二进制表示:01101100 01110011 01111001
  • 把3个8bit的字节变成4个6bit: 011011 000111 001101 111001
  • 把6bit进行补0:00011011 00000111 00001101 00111001
  • 得到Base64码的索引值:27 7 13 57
  • 得到Base64码:bHN5

如果要编码的值是一个十进制的1呢:

  • 1的ASCII码二进制表示:00110001
  • 把3个8bit的字节变成4个6bit,不足3个的补0: 001100 010000 000000 000000
  • 把6bit进行补0:00001100 00010000 00000000 00000000
  • 得到Base64码的索引值:12 16
  • 得到Base64码:MQ== (其中后两位为0,用=补上)

我们可以拿到这个结果值,到相应的Base64转码工具中查看,不出意外应该是一样的。

那回到一开始的那个题目。你会计算了吗? 其中char类型占1字节,就是8位,所能存储的正整数是 0111 1111,即127

答案见文后

ASCII码对照表

Bin(二进制)Oct(八进制)Dec(十进制)Hex(十六进制)缩写/字符解释
0000 00000000x00NUL(null)空字符
0000 00010110x01SOH(start of headline)标题开始
0000 00100220x02STX (start of text)正文开始
0000 00110330x03ETX (end of text)正文结束
0000 01000440x04EOT (end of transmission)传输结束
0000 01010550x05ENQ (enquiry)请求
0000 01100660x06ACK (acknowledge)收到通知
0000 01110770x07BEL (bell)响铃
0000 100001080x08BS (backspace)退格
0000 100101190x09HT (horizontal tab)水平制表符
0000 1010012100x0ALF (NL line feed, new line)换行键
0000 1011013110x0BVT (vertical tab)垂直制表符
0000 1100014120x0CFF (NP form feed, new page)换页键
0000 1101015130x0DCR (carriage return)回车键
0000 1110016140x0ESO (shift out)不用切换
0000 1111017150x0FSI (shift in)启用切换
0001 0000020160x10DLE (data link escape)数据链路转义
0001 0001021170x11DC1 (device control 1)设备控制1
0001 0010022180x12DC2 (device control 2)设备控制2
0001 0011023190x13DC3 (device control 3)设备控制3
0001 0100024200x14DC4 (device control 4)设备控制4
0001 0101025210x15NAK (negative acknowledge)拒绝接收
0001 0110026220x16SYN (synchronous idle)同步空闲
0001 0111027230x17ETB (end of trans. block)结束传输块
0001 1000030240x18CAN (cancel)取消
0001 1001031250x19EM (end of medium)媒介结束
0001 1010032260x1ASUB (substitute)代替
0001 1011033270x1BESC (escape)换码(溢出)
0001 1100034280x1CFS (file separator)文件分隔符
0001 1101035290x1DGS (group separator)分组符
0001 1110036300x1ERS (record separator)记录分隔符
0001 1111037310x1FUS (unit separator)单元分隔符
0010 0000040320x20(space)空格
0010 0001041330x21!叹号
0010 0010042340x22"双引号
0010 0011043350x23#井号
0010 0100044360x24$美元符
0010 0101045370x25%百分号
0010 0110046380x26&和号
0010 0111047390x27'闭单引号
0010 1000050400x28(开括号
0010 1001051410x29)闭括号
0010 1010052420x2A*星号
0010 1011053430x2B+加号
0010 1100054440x2C,逗号
0010 1101055450x2D-减号/破折号
0010 1110056460x2E.句号
0010 1111057470x2F/斜杠
0011 0000060480x300字符0
0011 0001061490x311字符1
0011 0010062500x322字符2
0011 0011063510x333字符3
0011 0100064520x344字符4
0011 0101065530x355字符5
0011 0110066540x366字符6
0011 0111067550x377字符7
0011 1000070560x388字符8
0011 1001071570x399字符9
0011 1010072580x3A:冒号
0011 1011073590x3B;分号
0011 1100074600x3C<小于
0011 1101075610x3D=等号
0011 1110076620x3E>大于
0011 1111077630x3F?问号
0100 00000100640x40@电子邮件符号
0100 00010101650x41A大写字母A
0100 00100102660x42B大写字母B
0100 00110103670x43C大写字母C
0100 01000104680x44D大写字母D
0100 01010105690x45E大写字母E
0100 01100106700x46F大写字母F
0100 01110107710x47G大写字母G
0100 10000110720x48H大写字母H
0100 10010111730x49I大写字母I
0100 10100112740x4AJ大写字母J
0100 10110113750x4BK大写字母K
0100 11000114760x4CL大写字母L
0100 11010115770x4DM大写字母M
0100 11100116780x4EN大写字母N
0100 11110117790x4FO大写字母O
0101 00000120800x50P大写字母P
0101 00010121810x51Q大写字母Q
0101 00100122820x52R大写字母R
0101 00110123830x53S大写字母S
0101 01000124840x54T大写字母T
0101 01010125850x55U大写字母U
0101 01100126860x56V大写字母V
0101 01110127870x57W大写字母W
0101 10000130880x58X大写字母X
0101 10010131890x59Y大写字母Y
0101 10100132900x5AZ大写字母Z
0101 10110133910x5B[开方括号
0101 11000134920x5C\反斜杠
0101 11010135930x5D]闭方括号
0101 11100136940x5E^脱字符
0101 11110137950x5F_下划线
0110 00000140960x60`开单引号
0110 00010141970x61a小写字母a
0110 00100142980x62b小写字母b
0110 00110143990x63c小写字母c
0110 010001441000x64d小写字母d
0110 010101451010x65e小写字母e
0110 011001461020x66f小写字母f
0110 011101471030x67g小写字母g
0110 100001501040x68h小写字母h
0110 100101511050x69i小写字母i
0110 101001521060x6Aj小写字母j
0110 101101531070x6Bk小写字母k
0110 110001541080x6Cl小写字母l
0110 110101551090x6Dm小写字母m
0110 111001561100x6En小写字母n
0110 111101571110x6Fo小写字母o
0111 000001601120x70p小写字母p
0111 000101611130x71q小写字母q
0111 001001621140x72r小写字母r
0111 001101631150x73s小写字母s
0111 010001641160x74t小写字母t
0111 010101651170x75u小写字母u
0111 011001661180x76v小写字母v
0111 011101671190x77w小写字母w
0111 100001701200x78x小写字母x
0111 100101711210x79y小写字母y
0111 101001721220x7Az小写字母z
0111 101101731230x7B{开花括号
0111 110001741240x7C|垂线
0111 110101751250x7D}闭花括号
0111 111001761260x7E~波浪号
0111 111101771270x7FDEL (delete)删除

Base64 字母对照表 (The Base64 Alphabet)

索引对应字符索引对应字符索引对应字符索引对应字符
0A17R34i51z
1B18S35j520
2C19T36k531
3D20U37l542
4E21V38m553
5F22W39n564
6G23X40o575
7H24Y41p586
8I25Z42q597
9J26a43r608
10K27b44s619
11L28c45t62+
12M29d46u63/
13N30e47v
14O31f48w
15P32g49x
16Q33h50y

题目答案

由于一个char字符就占一个byte,也就是8bit。所以原始字符二进制码长度为:12 * 8 = 96;因为原长度正好是3的倍数。 转换为6bit的二进制长度: 96 / 6 = 16; 如果长度为20:20 * 8 / 6 除不尽,原长度不是3的倍数。所以要把原厂度补为3的倍数。也就是21 * 8 / 6 = 28;

文章分类
前端
文章标签