为什么 fread() 函数没有到达文件末尾并且在从文件读取结构时循环无限继续?

Why the fread() function is not reaching the end-of-file and the loop continues infinitely, while reading structures from a file?

下面给出的代码片段是我用 C 编写的客户计费系统项目的一部分。在这里,我在客户结构中输入客户数据并将整个结构保存在 "CustomerRecord.dat" 文件使用我的代码中定义的 writefile() 函数。在我的文件中成功写入客户数据后,我尝试遍历文件并为每条记录分配客户编号。为此,我使用了代码中定义的 setCustomerNo() 函数。

问题是 setCustomerNo() 函数内的 while 循环是 运行 无限并且甚至在文件结束后读取。

请帮我解决这个问题。

我试过替换:

  1. while(!feof(fp) { // 循环体 }
  2. while(!feof(fp) && !ferror(fp)) { // 循环体 }
  3. while(fread(&x, sizeof(Customer), 1, fp) || !feof(fp)) { // 循环体 }

但是 none 以上这些替换对我有用。

#define RECORD CustomerRecord.dat
typedef struct
{
    int customerNo;
    unsigned int phoneNo;
    char name[20];
    char address[32];
    float balance;
}Customer;

void writefile(Customer x)
{
    FILE *fp;
    fp = fopen("CustomerRecord.dat", "ab");
    fwrite(&x, sizeof(Customer), 1, fp);
    fclose(fp);
}

Customer setCustomerNo()
{
    FILE *fp;
    Customer x, y;
    int k = 1;

    fp = fopen(RECORD, "rb+");
    while(!feof(fp) && !ferror(fp))
    {
        fread(&x, sizeof(Customer), 1, fp);
        x.customerNo = k++;
        y = x;
        fseek(fp, -sizeof(Customer), SEEK_CUR);
        fwrite(&x, sizeof(Customer), 1, fp);
    }
    fclose(fp);
    return y;
}

预期的结果是函数setCustomerNo()会从头读取文件中存储的所有结构,并更新customerNo(s)从1开始,依次类推到文件中存储的结构。最后 return 最后更新的结构。

您肯定不希望您的循环测试 feof(fp) —— 事实上,即 practically never right —— 因为如果循环结束时 feof(fp) 将始终为假,所以循环永远不会结束。为什么? fseek 联机帮助页详细说明:

A successful call to the fseek() function clears the end-of-file indicator for the stream.

无论如何,如果您考虑一下,您希望恰好在 fread 报告没有数据时终止循环。您当然不想处理 fread 未读取的 non-existent 数据。因此,在处理完可能未读的数据后测试是否存在 EOF 是不正确的,即使 feof(fp) 实际上返回了一个有用的值。


一些其他注意事项:

  1. 您最好使用 ftell 调用 read 之前的读取光标,然后 fseeking 到保存的点。这避免了一堆极端情况,并且很容易升级为使用更通用的 fseeko/ftello 函数,这些函数可以正常处理大文件。 (或者您可以直接使用 fseekoftello

  2. 想一想如果最后一个read是部分的,你想做什么。当然,如果您总是创建 fixed-length 记录,那 "can't happen"。但是 "can't happen" 最终所做的一切,出于某种原因。最好处理一下。