【问题标题】:fread Returns < 1 While Reading Record from Binary Filefread 从二进制文件中读取记录时返回 < 1
【发布时间】:2014-06-10 07:40:07
【问题描述】:

我正在尝试从二进制文件中读取学生记录 (SREC)。该文件肯定包含完整的记录(之前的运行写入文件)。在我的输出中,我收到两条记录的两次“错误:无法从文件中读取记录”语句。顶部的 printf(Reading record, numR) 显示 3 次,所以我知道 while 循环在应该到达 eof 时进入了 3 次。

有什么想法吗? 提前致谢!

/*Create and populate all 4 lists if lname list exists from previous usage*/
     if((readL = fopen("last", "rb")) == NULL)
     {
        printf("\nNew file will be created after server terminates.\n");
        created = 1;
     }
     else
        {           
        created = 0;

/*Read in record from binary file*/
        while(!feof(readL))
        {
            numR++;         
printf("Reading record %d\n", numR);

            /*Create new temporary SREC*/
            newSREC = (SREC*)malloc(sizeof(SREC));
            newSREC2 = (SREC*)malloc(sizeof(SREC));
            newSREC3 = (SREC*)malloc(sizeof(SREC));
            newSREC4 = (SREC*)malloc(sizeof(SREC));

            /*Read in one record from file*/
            if(fread(newSREC, sizeof(SREC), 1, readL) < 1)
            {
                newSREC2 = newSREC;
                newSREC3 = newSREC;
                newSREC4 = newSREC;

                firstL = insert(newSREC, 1, firstL);
                firstF = insert(newSREC2, 2, firstF);
                firstS = insert(newSREC3, 3, firstS);
                firstG = insert(newSREC4, 4, firstG);
            }
            else
            {
                printf("ERROR: Could not read record from file.\n");
            }
        }

        fclose(readL);
    }

【问题讨论】:

标签: c file-io binaryfiles fread feof


【解决方案1】:

表面问题

从表面上看,这段代码的错误检测是相反的:

if (fread(newSREC, sizeof(SREC), 1, readL) < 1)
{
    newSREC2 = newSREC;
    newSREC3 = newSREC;
    newSREC4 = newSREC;

    firstL = insert(newSREC, 1, firstL);
    firstF = insert(newSREC2, 2, firstF);
    firstS = insert(newSREC3, 3, firstS);
    firstG = insert(newSREC4, 4, firstG);
}
else
{
    printf("ERROR: Could not read record from file.\n");
}

如果读取了一条完整的记录,则fread()的返回值为1;否则它将为零。您应该使用:

if (fread(newSREC, sizeof(SREC), 1, readL) == 1)

深入研究

循环不应使用feof() — 请参阅while (!feof(file)) is always wrong。你应该使用类似的东西:

SREC srec;
while ((fread(&srec, sizeof(srec), 1, readL) == 1)
{
    SREC *newSREC1 = malloc(sizeof(*newSREC1));
    SREC *newSREC2 = malloc(sizeof(*newSREC2));
    SREC *newSREC3 = malloc(sizeof(*newSREC3));
    SREC *newSREC4 = malloc(sizeof(*newSREC4));
    if (newSREC1 == 0 || newSREC2 == 0 || newSREC3 == 0 || newSREC4 == 0)
    {
        free(newSREC1);
        free(newSREC2);
        free(newSREC3);
        free(newSREC4);
        …report error…
        break;
    }
    *newSREC1 = srec;
    *newSREC2 = srec;
    *newSREC3 = srec;
    *newSREC4 = srec;

    firstL = insert(newSREC1, 1, firstL);
    firstF = insert(newSREC2, 2, firstF);
    firstS = insert(newSREC3, 3, firstS);
    firstG = insert(newSREC4, 4, firstG);
}

// Optional analysis of why the loop ended — feof() vs ferror() vs short read

代码会泄漏内存,就像从来没有内存短缺一样。在分配了newSREC2 等之后,它用指向newSREC1 的指针覆盖了这些指针。作业 应该是:

*newSREC2 = *newSREC; // Original code — see above for revision

我注意到您不能在一个数组中分配所有 4 条记录,因为您几乎可以肯定需要能够独立释放 4 条记录。这会在代码中留下很多重复。

【讨论】:

    【解决方案2】:

    来自fread 手册页:

    fread() 不区分文件结束和错误,调用者必须使用 feof(3) 和 ferror(3) 来确定发生了什么。

    将您的测试更改为:

    while (fread(...) > 0)
        // ...
    
    if (ferror(file))
        // an error happened
    

    【讨论】:

      【解决方案3】:

      EOF 的错误指示器仅在尝试读取时设置。

      在您阅读的地方测试是否成功阅读。

      在您的示例中,测试是否恰好读取 1 条记录。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-22
        • 2019-04-13
        • 2019-10-01
        • 2016-04-19
        • 2020-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多