You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C语言中将文件内容写入内存缓冲区而非直接写入文件?

解决方案

首先明确:绝对不能直接执行send(client_socket, FILE, sizeof(FILE), 0)。FILE是C标准库的结构体,里面存的是文件操作的元数据(比如文件描述符、缓冲区状态、读写位置指针等),完全不是文件的实际内容,发送这个结构体给服务器毫无意义,对方根本还原不出原文件。

下面提供两种把文件内容读到内存(uint8_t数组)的实现方案,以及后续通过Socket发送的正确方式:

方法1:先获取文件大小,一次性分配内存读取

适合能提前确定文件大小的场景,步骤简洁高效:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

// 返回指向文件内容的uint8_t指针,out_size存储总字节数;失败返回NULL
uint8_t* read_file_to_memory(FILE* f_read, size_t* out_size) {
    if (!f_read || !out_size) return NULL;

    // 移动到文件末尾获取总字节数
    if (fseek(f_read, 0, SEEK_END) != 0) {
        perror("fseek failed");
        return NULL;
    }
    *out_size = ftell(f_read);
    if (*out_size == -1) {
        perror("ftell failed");
        return NULL;
    }
    // 移回文件开头准备读取
    rewind(f_read);

    // 分配对应大小的内存
    uint8_t* buffer = (uint8_t*)calloc(*out_size, sizeof(uint8_t));
    if (!buffer) {
        perror("malloc failed");
        return NULL;
    }

    // 一次性读取全部内容
    size_t bytes_read = fread(buffer, 1, *out_size, f_read);
    if (bytes_read != *out_size) {
        perror("fread incomplete");
        free(buffer);
        return NULL;
    }

    return buffer;
}

方法2:动态扩容缓冲区,边读边存

如果文件过大、无法提前获取大小(比如从管道/流读取的FILE*),用动态扩容更稳妥:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define INIT_BUFFER_SIZE 4096  // 初始缓冲区大小,可按需调整

uint8_t* read_file_to_memory_dynamic(FILE* f_read, size_t* out_size) {
    if (!f_read || !out_size) return NULL;

    size_t buffer_size = INIT_BUFFER_SIZE;
    uint8_t* buffer = (uint8_t*)malloc(buffer_size * sizeof(uint8_t));
    if (!buffer) {
        perror("malloc failed");
        return NULL;
    }

    *out_size = 0;
    uint8_t temp_buf[256];  // 和你原函数一致的临时读取缓冲区
    size_t bytes_read;

    while ((bytes_read = fread(temp_buf, 1, sizeof(temp_buf), f_read)) > 0) {
        // 内存不足时扩容(按2倍扩容,平衡效率和内存占用)
        if (*out_size + bytes_read > buffer_size) {
            buffer_size *= 2;
            uint8_t* new_buffer = (uint8_t*)realloc(buffer, buffer_size);
            if (!new_buffer) {
                perror("realloc failed");
                free(buffer);
                return NULL;
            }
            buffer = new_buffer;
        }
        // 将临时缓冲区内容拷贝到主内存块
        memcpy(buffer + *out_size, temp_buf, bytes_read);
        *out_size += bytes_read;
    }

    // 可选:将缓冲区缩小到实际使用大小,节省内存
    uint8_t* final_buffer = (uint8_t*)realloc(buffer, *out_size);
    if (final_buffer) buffer = final_buffer;

    return buffer;
}

内存内容通过Socket发送

拿到内存中的文件数据和大小后,不能直接一次send就结束——因为网络原因,send可能只发送了部分字节,必须循环发送直到全部发完:

#include <sys/socket.h>

// 发送内存中的全部数据,返回已发送总字节数;失败返回-1
ssize_t send_all(int sockfd, const uint8_t* data, size_t total_size) {
    size_t sent = 0;
    while (sent < total_size) {
        ssize_t ret = send(sockfd, data + sent, total_size - sent, 0);
        if (ret == -1) {
            perror("send failed");
            return -1;
        }
        sent += ret;
    }
    return sent;
}

完整使用示例

int main() {
    FILE* fp = fopen("test.pdf", "rb");
    if (!fp) {
        perror("fopen failed");
        return 1;
    }

    size_t file_size;
    // 二选一:用一次性读取或动态扩容版本
    uint8_t* file_data = read_file_to_memory(fp, &file_size);
    // uint8_t* file_data = read_file_to_memory_dynamic(fp, &file_size);

    if (file_data) {
        // 假设你已成功建立client_socket连接
        if (send_all(client_socket, file_data, file_size) == file_size) {
            printf("文件发送完成\n");
        }
        // 用完记得释放内存
        free(file_data);
    }

    fclose(fp);
    return 0;
}

内容的提问来源于stack exchange,提问作者CPPSauce

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 02:06:25