socket读取内容写入本地文件末尾数据缺失问题排查
问题分析与修复方案
嘿,我一眼就揪出问题所在了——你用错了写入文件的函数!
核心问题
你用fprintf(new_file, "%s", buffer)来写入从socket读取的内容,但%s格式符是专门处理以\0结尾的C字符串的,可从socket读取的原始数据(哪怕是HTML文本)完全不保证带有这个终止符:
- 如果读取的字节里恰好包含
\0,fprintf会在这个位置直接停止写入,导致后面的内容全部丢失; - 如果buffer的有效数据后面没有
\0,fprintf会越界读取内存,这属于未定义行为,可能写入乱码,或者直接截断内容; - 你原代码里的
if(bytes_read < MAXSIZE) break;逻辑也有问题,提前中断循环可能漏掉后续的分段数据。
而printf("%s", buffer)看起来正常,只是终端输出对\0不敏感,刚好你的显示部分没碰到这个问题而已,属于巧合。
修复后的代码
把fprintf换成fwrite,它能精确写入你实际读取到的字节数,完全不依赖字符串终止符。同时调整循环逻辑,去掉不必要的memset:
#define MAXSIZE 1000 int bytes_read, thread_fd; char buffer[MAXSIZE]; FILE* new_file; if((new_file = fopen(path, "wb+")) == NULL) { printf("can not open file \n"); exit(EXIT_FAILURE); } // 每次读取后直接写入精确字节数,无需清空buffer while ((bytes_read = read(thread_fd, buffer, MAXSIZE)) > 0) { // fwrite参数:数据源、单个元素大小、元素数量、目标文件 fwrite(buffer, 1, bytes_read, new_file); // 删掉原有的break逻辑——read返回0表示连接关闭,返回-1是错误,小于MAXSIZE是正常的分段传输 } // 务必关闭文件,确保缓冲区内容全部刷入磁盘 fclose(new_file);
额外说明
- 删掉提前break的逻辑:socket传输经常会分多批发送小于MAXSIZE的数据,提前中断会导致后续数据丢失;
- 无需memset清空buffer:
fwrite只会写入你指定的bytes_read字节,buffer后面的残留数据根本不会被处理,清空操作纯粹浪费性能; - 一定要关闭文件:原代码没写
fclose,会导致文件缓冲区的剩余内容无法刷新到磁盘,这也是内容缺失的潜在原因。
内容的提问来源于stack exchange,提问作者Darren Col




