Base64的原理:
解析一:就是把3个8位的char,通过位运算,变成4个6位的char。再经过高两位,也就是把256个选择变成了64个选择。而64个刚好是ASCII码中可以用来输出的64个字符,大小写英文字母52个+10个数字+两个特殊字符‘+’和‘/’,。
解析二:Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
总结:用一句话来说明Base64编码的原理:“把3个字节变成4个字节”。
比如某一字符串转成字节码为:
11011001 01101010 00101100
110110010110101000101100
00110110 00010110 00101000 00101100
把8位的字节连成一串110110010110101000101100
然后每次顺序选6个出来之后再把这6二进制数前面再添加两个0,就成了一个新的字节。之后再选出6个来,再添加0,依此类推,直到24个二进制数全部被选完。
当代码量不是3的整数倍时,代码量/3的余数自然就是2或者1。转换的时候,结果不够6位的在后面用0来补上相应的位置,之后再在6位的前面补两个0。转换完空出的结果就用就用“=”来补位。
如果余1,就补“==”
如果余2,就补“=”
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
class Base64
{
public:
Base64()
{
m_code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
};
//编码为base64
std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
{
std::string encode;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--)
{
char_array_3[i++] = *(bytes_to_encode++);
if(i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);//第一个char的后两位加后一个char的高四位
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);//第二个char的后四位+第三个char的高两位
char_array_4[3] = char_array_3[2] & 0x3f;//第三个char的低六位
for(i = 0; (i <4) ; i++)
encode += m_code[char_array_4[i]];
i = 0;
}
}
if(i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
encode += m_code[char_array_4[j]];
while((i++ < 3))
encode += '=';
}
return encode;
};
//进行base64解码
std::string base64_decode(std::string const &encoded_string)
{
int in_len = encoded_string.size();
int i = 0;
int j = 0;
int in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string decode;
while(in_len--
&& (encoded_string[in_] != '=')
&& is_base64(encoded_string[in_])
)
{
char_array_4[i++] = encoded_string[in_]; in_++;
if(i ==4)
{
for(i = 0; i <4; i++)
char_array_4[i] = m_code.find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for(i = 0; (i < 3); i++)
decode += char_array_3[i];
i = 0;
}
}
if(i)
{
for(j = i; j <4; j++)
char_array_4[j] = 0;
for(j = 0; j <4; j++)
char_array_4[j] = m_code.find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for(j = 0; (j < i - 1); j++)
decode += char_array_3[j];
}
return decode;
};
private:
inline bool is_base64(unsigned char c)
{
return (isalnum(c) || (c == '+') || (c == '/'));
};
private:
std::string m_code;
};
int main()
{
//Base64 bs64;
std::fstream f;
f.open("1.jpg", std::ios::in | std::ios::binary);
if(!f.is_open())
{
cout<<"File open failed."<<endl;
f.close(); //关闭文件以保存其内容
}
f.seekg(0, std::ios_base::end); //设置偏移量至文件结尾
std::streampos sp = f.tellg(); //获取文件大小
int size = sp;
char* buffer = (char*)malloc(sizeof(char) * size);
f.seekg(0, std::ios_base::beg); //设置偏移量至文件开头
f.read(buffer, size); //将文件内容读入buffer
std::string imgBase64 =Base64().base64_encode((unsigned char const *)buffer, size);
std::string s_mat = Base64().base64_decode(imgBase64.c_str());
f.close();
FILE* stream;
if ((stream = fopen("2.jpg", "wb")) != NULL)
{
//将解码后的数据写入新文件
int numwritten = fwrite(s_mat.data(), sizeof(char), s_mat.size(), stream);
fclose(stream);
}
return 0;
}
要考虑到的一点是,编解码有时候不会一次性完成,为什么呢,实际情况中,要编解码的字符串可能很长,你不可能把字符串一次性读到内存中,因此就要分批编解码,但是我们编码是以3个字节为一组进行编码,因此,在类中需要设置一个缓存,长度为3,当缓存满了,就直接让3个字节去编码。