为什么 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 循环是 运行 无限并且甚至在文件结束后读取。
请帮我解决这个问题。
我试过替换:
- while(!feof(fp) { // 循环体 }
- while(!feof(fp) && !ferror(fp)) { // 循环体 }
- 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)
实际上返回了一个有用的值。
一些其他注意事项:
您最好使用 ftell
调用 read
之前的读取光标,然后 fseek
ing 到保存的点。这避免了一堆极端情况,并且很容易升级为使用更通用的 fseeko/ftello
函数,这些函数可以正常处理大文件。 (或者您可以直接使用 fseeko
和 ftello
。
想一想如果最后一个read
是部分的,你想做什么。当然,如果您总是创建 fixed-length 记录,那 "can't happen"。但是 "can't happen" 最终所做的一切,出于某种原因。最好处理一下。
下面给出的代码片段是我用 C 编写的客户计费系统项目的一部分。在这里,我在客户结构中输入客户数据并将整个结构保存在 "CustomerRecord.dat" 文件使用我的代码中定义的 writefile() 函数。在我的文件中成功写入客户数据后,我尝试遍历文件并为每条记录分配客户编号。为此,我使用了代码中定义的 setCustomerNo() 函数。
问题是 setCustomerNo() 函数内的 while 循环是 运行 无限并且甚至在文件结束后读取。
请帮我解决这个问题。
我试过替换:
- while(!feof(fp) { // 循环体 }
- while(!feof(fp) && !ferror(fp)) { // 循环体 }
- 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)
实际上返回了一个有用的值。
一些其他注意事项:
您最好使用
ftell
调用read
之前的读取光标,然后fseek
ing 到保存的点。这避免了一堆极端情况,并且很容易升级为使用更通用的fseeko/ftello
函数,这些函数可以正常处理大文件。 (或者您可以直接使用fseeko
和ftello
。想一想如果最后一个
read
是部分的,你想做什么。当然,如果您总是创建 fixed-length 记录,那 "can't happen"。但是 "can't happen" 最终所做的一切,出于某种原因。最好处理一下。