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

C语言文件处理疑问:以1字节读取文件时大小计算为何不一致?

问题原因分析

你的问题主要来自两个核心点:文本模式的换行转换和**feof()的逻辑误用**,咱们逐个拆解:

1. 文本模式导致字节数与读取字符数不匹配

你用"r"模式打开文件,这属于文本模式。在Windows系统中,文本模式下会自动把文件里的\r\n(占2个字节的Windows换行符)转换成单个\n字符(占1个字节的Unix风格换行)。

你通过fseek+ftell得到的size=78是文件的实际磁盘字节数,但在文本模式读取时,每遇到一组\r\n就会少读1个字节。如果你的文件里正好有2组这样的换行,实际读取的字符数就会是78-2=76,这和你第二次输出的结果完全对应。

2. feof()的常见误区

feof()的作用不是“预判是否到文件末尾”,而是判断上一次读取操作是否因为到达末尾而失败。你的循环条件!feof(file)会导致循环多执行一次:
当读完最后一个有效字符时,feof()仍然返回假,循环会继续执行。此时fread()读取失败(返回0),但你还是执行了size = i + 1——不过在你的案例里,这个问题被文本模式的换行转换掩盖了,因为实际读取的字符数本身就比字节数少。

解决办法

针对这两个问题,你可以这样修改代码:

方案一:用二进制模式打开文件

如果你的文件是二进制文件,或者你需要精确读取所有字节,把打开模式改成"rb":

errno_t err = fopen_s(&file,"f.txt","rb");

二进制模式不会进行任何换行转换,ftell()得到的字节数和实际读取的字节数会完全一致。

方案二:用fread()返回值判断循环

不管是文本还是二进制模式,都应该依赖fread()的返回值判断是否读取成功,而不是feof():

int i = 0;
size_t read_count;
while ((read_count = fread(tmp + i, 1, 1, file)) == 1) {
    i++;
}
size = i;

这样能准确统计实际读取的字符数,避免feof()带来的循环多执行问题。

完整优化后的代码

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

int main(void) {
    FILE * file;
    errno_t err = fopen_s(&file,"f.txt","rb"); // 二进制模式打开
    if (err != 0) { // 必须检查文件是否成功打开
        printf("Failed to open file\n");
        return 1;
    }
    fseek(file, 0, SEEK_END);
    long size = ftell(file); // 用long存储更安全,避免int溢出
    fseek(file, 0, SEEK_SET);
    char *tmp = malloc(size);
    if (tmp == NULL) { // 检查内存分配是否成功
        printf("Memory allocation failed\n");
        fclose(file);
        return 1;
    }
    printf("%ld\n", size);
    int i = 0;
    size_t read_count;
    while ((read_count = fread(tmp + i, 1, 1, file)) == 1) {
        i++;
    }
    size = i;
    printf("%d\n", size);
    fclose(file);
    free(tmp);
    return 0;
}

额外提醒:一定要检查fopen_s()和malloc()的返回值,避免空指针导致程序崩溃;ftell()返回的是long类型,用int存储可能会溢出,建议用long处理文件大小。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 16:17:50