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

使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:00:00