使用fread读取二进制文件丢失数据,请求排查代码问题
解决fread读取二进制文件不完整+TCP发送的常见问题
嘿,我太懂你这种折腾半天没解决的头疼感了——二进制文件用fread读不全,试遍各种方法都没用对吧?咱们从几个最容易踩的坑开始排查,尤其是fread的校验和文件操作环节,大概率问题就出在这儿。
1. 先检查文件打开模式!这是最容易犯的低级错误
如果你打开文件用的是"r"而不是"rb",在Windows系统下会直接踩两个坑:
- 把二进制里的
\x1A(EOF控制字符)当成文件结束标志,直接截断读取 - 自动把
\r\n转换成\n,破坏二进制文件的原始内容
错误示例:
FILE *fp = fopen("file.bin", "r");
正确打开方式:FILE *fp = fopen("file.bin", "rb");
2. fread的返回值校验绝对不能偷懒
很多人只判断fread(...) == 0就认为读完了,但fread的返回值是实际读取的元素个数(不是字节数!)。当读取到文件末尾或出错时,返回值会小于你请求的元素数,这时候必须结合feof和ferror判断到底是正常读完还是读取出错。
举个正确的循环读取+发送的示例(按字节读取,每个元素1字节):
#define BUFFER_SIZE 4096 char buffer[BUFFER_SIZE]; size_t bytes_read; // 循环读取文件内容 while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, fp)) > 0) { // TCP发送必须循环,因为send不一定能一次性发完所有字节 size_t bytes_sent = 0; while (bytes_sent < bytes_read) { ssize_t ret = send(sockfd, buffer + bytes_sent, bytes_read - bytes_sent, 0); if (ret == -1) { perror("send failed"); fclose(fp); exit(EXIT_FAILURE); } bytes_sent += ret; } } // 循环结束后判断是正常读完还是出错 if (ferror(fp)) { perror("fread failed"); fclose(fp); exit(EXIT_FAILURE); } fclose(fp);
这里要注意两个关键点:
- 绝对不能假设fread一次就能读完整个文件,大文件必须循环读取
- 每次发送必须用fread返回的
bytes_read(实际读取的字节数),而不是直接用缓冲区大小
3. TCP发送的特性容易被忽略,别让背锅给fread
TCP是流式协议,send函数的返回值是实际发送的字节数,它不一定能把你传入的所有字节一次性发出去。哪怕fread读对了内容,如果发送时没循环处理,接收端也会收到不完整的数据——这锅可能根本不是fread的!
4. 其他可能的小坑
- 文件权限问题:如果程序没有读取目标文件的权限,fread会返回0或出错,用
ferror可以排查 - 缓冲区大小不合理:如果缓冲区太大,fread可能返回的元素数小于预期,但循环读取就能解决
- 未正确关闭文件:虽然不会直接导致读不全,但可能存在缓存未刷新的问题,读完后一定要调用
fclose(fp)
如果能把你的具体代码贴出来,我可以帮你更精准地定位问题,但先把上面这几个点排查一遍,大概率能解决你的困扰。
内容的提问来源于stack exchange,提问作者Erik
相关产品推荐
相关产品推荐

