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
- 字符串"Man"的ASCII码是:
-
分成6位块:
- 划分后得到:
010011 010110 000101 101110
- 划分后得到:
-
转换为十进制:
- 每个6位块对应的整数是:
19 22 5 46
- 每个6位块对应的整数是:
-
映射到Base64字符集:
- 使用Base64字符表对应的字符是:
T W F u
- 使用Base64字符表对应的字符是:
因此,字符串"Man"被Base64编码后就是"TWFu"。
处理不足3字节的数据
假设我们要编码字符串"Ma"。
-
输入数据:
- 字符串"Ma"的ASCII码是:
M: 77 (01001101) a: 97 (01100001)
- 字符串"Ma"的ASCII码是:
-
补齐到3字节:
- 补齐后变成:
01001101 01100001 00000000
- 补齐后变成:
-
分成6位块:
- 划分后得到:
010011 010110 000100 000000
- 划分后得到:
-
转换为十进制:
- 每个6位块对应的整数是:
19 22 16 0
- 每个6位块对应的整数是:
-
映射到Base64字符集:
- 使用Base64字符表对应的字符是:
T W Q A
- 使用Base64字符表对应的字符是:
-
添加填充字符:
- 因为原始数据不足3字节,我们在末尾添加一个等号(
=
),表示有1字节填充。 - 最终结果是:
TWFu==
- 因为原始数据不足3字节,我们在末尾添加一个等号(
解码过程
解码过程与编码过程相反,分以下几步:
-
移除填充字符:
- 移除结尾的等号(
=
)。
- 移除结尾的等号(
-
转换Base64字符为6位块:
- 将每个Base64字符转换回对应的6位二进制块。
-
重新组合为8位块:
- 将6位块重新组合成8位块。
-
转换为原始字节:
- 将8位块转回原始的字节数据。
通过这些步骤,Base64编码和解码可以在文本和二进制数据之间无损转换。
读懂这段代码!
#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;
}