Base64是一种常用的编码方式,用于将二进制数据转换为文本格式。它常用于在需要通过文本传输二进制数据的场景中,例如在电子邮件和URL中传递二进制文件。Base64的核心原理如下:
原理
-
输入数据分组:
- 将输入的二进制数据按字节分成每组3字节(24位)。
-
转换为6位块:
- 将每3字节(24位)的数据块分成4个6位块。这样,每个6位块可以表示一个范围在0到63之间的整数。
-
映射到Base64字符集:
- 使用Base64字符表将每个6位块映射到一个Base64字符。Base64字符集包含64个字符,包括大写字母A-Z,小写字母a-z,数字0-9,以及两个特殊字符"+"和"/"。
-
处理不足3字节的数据:
- 如果最后一组数据不足3字节,则用0字节填充,以保证数据长度是3的倍数。编码后,用一个或两个等号(
=
)填充,以表明原始数据的长度。
- 如果最后一组数据不足3字节,则用0字节填充,以保证数据长度是3的倍数。编码后,用一个或两个等号(
Base64字符表
Base64字符表如下:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
示例
假设我们要编码字符串"Man"。
-
输入数据:
-
字符串"Man"的ASCII码是:
M: 77 (01001101) a: 97 (01100001) n: 110 (01101110)
-
合并成二进制数据:
01001101 01100001 01101110
-
-
分成6位块:
-
划分后得到:
010011 010110 000101 101110
-
-
转换为十进制:
-
每个6位块对应的整数是:
19 22 5 46
-
-
映射到Base64字符集:
-
使用Base64字符表对应的字符是:
T W F u
-
因此,字符串"Man"被Base64编码后就是"TWFu"。
处理不足3字节的数据
假设我们要编码字符串"Ma"。
-
输入数据:
-
字符串"Ma"的ASCII码是:
M: 77 (01001101) a: 97 (01100001)
-
-
补齐到3字节:
-
补齐后变成:
01001101 01100001 00000000
-
-
分成6位块:
-
划分后得到:
010011 010110 000100 000000
-
-
转换为十进制:
-
每个6位块对应的整数是:
19 22 16 0
-
-
映射到Base64字符集:
-
使用Base64字符表对应的字符是:
T W Q A
-
-
添加填充字符:
-
因为原始数据不足3字节,我们在末尾添加一个等号(
=
),表示有1字节填充。 -
最终结果是:
TWFu==
-
解码过程
解码过程与编码过程相反,分以下几步:
-
移除填充字符:
- 移除结尾的等号(
=
)。
- 移除结尾的等号(
-
转换Base64字符为6位块:
- 将每个Base64字符转换回对应的6位二进制块。
-
重新组合为8位块:
- 将6位块重新组合成8位块。
-
转换为原始字节:
- 将8位块转回原始的字节数据。
通过这些步骤,Base64编码和解码可以在文本和二进制数据之间无损转换。
读懂这段代码!
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Base64编码表
static const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
// 判断字符是否为Base64编码字符
int is_base64(unsigned char c) {
return (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c == '+') || (c == '/');
}
// Base64编码函数
char *base64_encode(const unsigned char *data, size_t input_length, size_t *output_length) {
// 计算编码后的字符串长度
*output_length = 4 * ((input_length + 2) / 3);
// 为输出字符串分配内存
char *encoded_data = (char *)malloc(*output_length + 1);
if (encoded_data == NULL) return NULL;
// 编码过程
for (size_t i = 0, j = 0; i < input_length;) {
uint32_t octet_a = i < input_length ? data[i++] : 0;
uint32_t octet_b = i < input_length ? data[i++] : 0;
uint32_t octet_c = i < input_length ? data[i++] : 0;
uint32_t triple = (octet_a << 16) | (octet_b << 8) | octet_c;
encoded_data[j++] = base64_chars[(triple >> 18) & 0x3F];
encoded_data[j++] = base64_chars[(triple >> 12) & 0x3F];
encoded_data[j++] = base64_chars[(triple >> 6) & 0x3F];
encoded_data[j++] = base64_chars[triple & 0x3F];
}
// 添加填充字符
for (size_t i = 0; i < (3 - input_length % 3) % 3; i++) {
encoded_data[*output_length - 1 - i] = '=';
}
// 添加字符串终止符
encoded_data[*output_length] = '\0';
return encoded_data;
}
// 测试函数
int main() {
const char *text = "Hello, World!";
size_t input_length = strlen(text);
size_t output_length;
// Base64编码
char *encoded_text = base64_encode((const unsigned char *)text, input_length, &output_length);
if (encoded_text == NULL) {
fprintf(stderr, "内存分配失败\n");
return 1;
}
// 输出编码后的字符串
printf("Base64编码后的结果:%s\n", encoded_text);
// 释放内存
free(encoded_text);
return 0;
}