C语言实现文件转Base64编码字符串

来自姬鸿昌的知识库
Jihongchang讨论 | 贡献2025年8月20日 (三) 03:14的版本 (建立内容为“file_to_base64.c<syntaxhighlight lang="c"> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> // 用于获取文件大小 // Base64…”的新页面)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳到导航 跳到搜索

file_to_base64.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> // 用于获取文件大小

// Base64编码表
const char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// 计算Base64编码后的长度
size_t base64_encoded_length(size_t input_len) {
    return (input_len + 2) / 3 * 4;
}

// 将二进制数据转换为Base64编码
char* data_to_base64(const unsigned char* input, size_t input_len) {
    // 计算输出缓冲区大小并分配内存
    size_t output_len = base64_encoded_length(input_len);
    char* output = (char*)malloc(output_len + 1); // +1 用于存储终止符
    if (output == NULL) {
        return NULL; // 内存分配失败
    }

    int i, j;
    for (i = 0, j = 0; i < input_len; i += 3, j += 4) {
        // 读取3个字节,不足的用0填充
        unsigned char byte1 = input[i];
        unsigned char byte2 = (i + 1 < input_len) ? input[i + 1] : 0;
        unsigned char byte3 = (i + 2 < input_len) ? input[i + 2] : 0;

        // 将3个8位字节转换为4个6位值
        unsigned int val = (byte1 << 16) | (byte2 << 8) | byte3;

        // 提取每个6位值并映射到Base64字符
        output[j] = base64_chars[(val >> 18) & 0x3F];
        output[j + 1] = base64_chars[(val >> 12) & 0x3F];

        // 处理填充字符'='
        output[j + 2] = (i + 1 < input_len) ? base64_chars[(val >> 6) & 0x3F] : '=';
        output[j + 3] = (i + 2 < input_len) ? base64_chars[val & 0x3F] : '=';
    }

    output[output_len] = '\0'; // 添加字符串终止符
    return output;
}

// 获取文件大小
long get_file_size(const char* filename) {
    struct stat file_info;
    if (stat(filename, &file_info) != 0) {
        return -1; // 获取文件信息失败
    }
    return file_info.st_size;
}

// 从文件读取数据到缓冲区
unsigned char* read_file_to_buffer(const char* filename, long* file_size) {
    FILE* file = fopen(filename, "rb"); // 以二进制模式打开
    if (file == NULL) {
        perror("无法打开文件");
        return NULL;
    }

    // 获取文件大小
    *file_size = get_file_size(filename);
    if (*file_size < 0) {
        perror("无法获取文件大小");
        fclose(file);
        return NULL;
    }

    // 分配缓冲区
    unsigned char* buffer = (unsigned char*)malloc(*file_size);
    if (buffer == NULL) {
        perror("内存分配失败");
        fclose(file);
        return NULL;
    }

    // 读取文件内容
    size_t bytes_read = fread(buffer, 1, *file_size, file);
    if (bytes_read != *file_size) {
        perror("文件读取失败");
        free(buffer);
        fclose(file);
        return NULL;
    }

    fclose(file);
    return buffer;
}

// 将文件转换为Base64编码并输出
int file_to_base64(const char* filename, int output_to_file, const char* output_filename) {
    long file_size;
    unsigned char* file_data = read_file_to_buffer(filename, &file_size);
    if (file_data == NULL) {
        return 1; // 读取文件失败
    }

    // 转换为Base64
    char* base64_str = data_to_base64(file_data, file_size);
    if (base64_str == NULL) {
        perror("Base64编码失败");
        free(file_data);
        return 1;
    }

    // 输出结果
    if (output_to_file && output_filename != NULL) {
        // 输出到文件
        FILE* out_file = fopen(output_filename, "w");
        if (out_file == NULL) {
            perror("无法打开输出文件");
            free(file_data);
            free(base64_str);
            return 1;
        }

        fputs(base64_str, out_file);
        fclose(out_file);
        printf("Base64编码已保存到 %s\n", output_filename);
    }
    else {
        // 输出到控制台
        printf("文件 %s 的Base64编码:\n", filename);
        printf("%s\n", base64_str);
    }

    // 清理内存
    free(file_data);
    free(base64_str);
    return 0;
}

int main(int argc, char* argv[]) {
    // 检查命令行参数
    if (argc < 2) {
        printf("用法: %s <文件名> [输出文件名]\n", argv[0]);
        printf("如果提供输出文件名,则将Base64编码保存到文件,否则输出到控制台\n");
        return 1;
    }

    const char* input_filename = argv[1];
    const char* output_filename = (argc >= 3) ? argv[2] : NULL;

    // 执行转换
    return file_to_base64(input_filename, (argc >= 3), output_filename);
}