如何在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
相关产品推荐
相关产品推荐

