Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
可用于网络传输二进制数据(图片,文件...),将二进制转为Base64编码后,可以写入XML,将XML传输到Server端,再进行Base64解码,得到二进制数据。(二进制不能直接写入XML,Base64字符才可以。)
Base64适用于小段内容的编码,比如数字证书签名、Cookie的内容等。
标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。为解决此问题,可采用一种用于URL的改进Base64编码,它在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
关于编码的规则:
①.把3个字节变成4个字节。
② 每76个字符加一个换行符。(可选,编码解码一致即可)
③.最后的结束符也要处理。(若字节数是3的倍数正好,若字节数 n%3=1, 在结尾补“==”,n%3=2时,在结尾补“=”)
例子1
转换前 11111111, 11111111, 11111111 (二进制)
转换后 00111111, 00111111, 00111111, 00111111 (二进制)
上面的三个字节是原文,下面的四个字节是转换后的Base64编码,其前两位均为0。
转换后,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码),这个表是这样的:(十进制 <--> 字符)
索引
|
对应字符
|
索引
|
对应字符
|
索引
|
对应字符
|
索引
|
对应字符
|
0
|
A
|
17
|
R
|
34
|
i
|
51
|
z
|
1
|
B
|
18
|
S
|
35
|
j
|
52
|
0
|
2
|
C
|
19
|
T
|
36
|
k
|
53
|
1
|
3
|
D
|
20
|
U
|
37
|
l
|
54
|
2
|
4
|
E
|
21
|
V
|
38
|
m
|
55
|
3
|
5
|
F
|
22
|
W
|
39
|
n
|
56
|
4
|
6
|
G
|
23
|
X
|
40
|
o
|
57
|
5
|
7
|
H
|
24
|
Y
|
41
|
p
|
58
|
6
|
8
|
I
|
25
|
Z
|
42
|
q
|
59
|
7
|
9
|
J
|
26
|
a
|
43
|
r
|
60
|
8
|
10
|
K
|
27
|
b
|
44
|
s
|
61
|
9
|
11
|
L
|
28
|
c
|
45
|
t
|
62
|
+
|
12
|
M
|
29
|
d
|
46
|
u
|
63
|
/
|
13
|
N
|
30
|
e
|
47
|
v
|
||
14
|
O
|
31
|
f
|
48
|
w
|
||
15
|
P
|
32
|
g
|
49
|
x
|
||
16
|
Q
|
33
|
h
|
50
|
y
|
例子2
转换前 10101101,10111010,01110110
转换后 00101011, 00011011 ,00101001 ,00110110
十进制 43 27 41 54
对应码表中的值 r b p 2
所以上面的24位编码,编码后的Base64值为 rbp2
解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。
//用更接近于编程的思维来说,编码的过程是这样的: //第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。 //然后将第一个字符与0x03(00000011)进行与(&)操作并左移4位,接着第二个字符右移4位,两者相或(|),或者相加,即获得第二个目标字符。 //再将第二个字符与0x0f(00001111)进行与(&)操作并左移2位,接着第三个字符右移6位,两者相或(|),或者相加,即获得第三个目标字符。 //最后将第三个字符与0x3f(00111111)进行与(&)操作,即获得第四个目标字符。 //在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。
C++代码实现
特别注意,按位左移和右移,必须是 unsigned char 。可以定义 typedef unsigned char BYTE;
const char* Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxwz0123456789+/"; std::string Base64encode(const unsigned char* buf, unsigned int size) { std::string sBase64; unsigned int i; for (i = 0; i < size/3*3; i += 3) { sBase64 += Base64[buf[i] >> 2]; sBase64 += Base64[(buf[i]<<4 | buf[i+1]>>4) & 0x3f]; sBase64 += Base64[(buf[i+1]<<2 | buf[i+2]>>6) & 0x3f]; sBase64 += Base64[buf[i+2] & 0x3f]; } if (size % 3 == 1) { sBase64 += Base64[buf[i] >> 2]; sBase64 += Base64[buf[i]<<4 & 0x3f]; sBase64 += '='; sBase64 += '='; } else if (size % 3 == 2) { sBase64 += Base64[buf[i] >> 2]; sBase64 += Base64[(buf[i]<<4 | buf[i+1]>>4) & 0x3f]; sBase64 += Base64[buf[i+1]<<2 & 0x3f]; sBase64 += '='; } return sBase64; } std::string Base64decode(std::string sBase64) { std::string sRet; unsigned int nLen = sBase64.size();//nLen一定是4的倍数 unsigned char* a = new unsigned char[nLen]; int count = 0; // the number of '='. for (unsigned i = 0; i < nLen; ++i) { if (sBase64[i] >= 'A' && sBase64[i] <= 'Z') a[i] = sBase64[i] - 'A'; else if (sBase64[i] >= 'a' && sBase64[i] <= 'z') a[i] = sBase64[i] - 'a' + 26; else if (sBase64[i] >= '0' && sBase64[i] <= '9') a[i] = sBase64[i] - '0' + 52; else if ('+' == sBase64[i]) a[i] = 62; else if ('/' == sBase64[i]) a[i] = 63; else if ('=' == sBase64[i]) { a[i] = 0; count++; } } sRet.resize(nLen/4*3); unsigned j = 0; for (unsigned i = 0; i < nLen; i += 4) { sRet[j++] = a[i]<<2 | a[i+1]>>4; sRet[j++] = a[i+1]<<4 | a[i+2]>>2; sRet[j++] = a[i+2]<<6 | a[i+3]; } delete[] a; assert(j == nLen / 4 * 3); if (count) sRet.resize(sRet.size() - count); return sRet; } int main() { //std::string s("ixb7x1dxfbxefxffi");//-> abcd++//aQ== //std::string s("x00x3fxbfxd7m",5);//-> AD+/120= std::string s("abcde"); // -> YWJjZGU= std::string r = Base64encode((const unsigned char*)s.c_str(), s.size()); std::string sRet = Base64decode(r); return 0; }
方法2:
std::string Base64encode(const unsigned char* buf, unsigned int size) { //方法二 typedef unsigned char BYTE; std::string sBase64; std::basic_string<BYTE> s(buf, buf+size); unsigned count = 0;//不足3的倍数,补 的个数,即编码后“=”个数。 if (size % 3 == 1) { s.push_back('