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

标签 c structure file-handling data-files

下面给出的代码片段是我用 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)) {//循环体 }

但以上这些替代品都不适合我。

#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()会从头读取文件中存储的所有结构,并更新从1开始的customerNo(s)等到文件中存储的结构。最后返回最后更新的结构。

最佳答案

您肯定不希望您的循环测试feof(fp)——事实上,那是practically never right -- 因为 feof(fp) 在循环结束时总是 false,所以循环永远不会结束。为什么? fseek 联机帮助页详细说明:

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

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


一些其他注意事项:

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

  2. 想想如果最后的read 是部分的,你想做什么。当然,如果您总是创建固定长度的记录,那“不可能发生”。但是,出于某种原因,“不可能发生”的一切最终都会发生。最好处理一下。

关于c - 为什么 fread() 函数没有到达文件末尾并且在从文件读取结构时循环无限继续?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57069236/

相关文章:

c - 这是一个 clang 错误吗? typedef 的匿名结构

c++ - 初始化结构 vector

c++ - 如何将字符空间动态分配给结构字段

java - 如何修复线程 "main"java.io.EOFException 中的异常? (java套接字)

c - 如何将字符串返回给另一个函数?

c - 递归不听 Return 而是 Exit(0)

c - 修改 strace 以捕获并替换打开的系统调用中的文件名

c++ - 如何复制结构(这是结构中的结构)并将其填充到C++中的结构数组中

c - 从 C 中的文件读取值时出现垃圾

c - 从 C 中的文本文件中查找并保存一个整数