下面给出的代码段是我用C语言编写的“客户计费系统”项目的一部分。在这里,我将客户数据输入到“客户”结构中,并将整个结构保存在“ CustomerRecord.dat”中使用我的代码中定义的writefile()函数创建文件。在将客户数据成功写入文件后,我试图遍历文件并为每条记录分配客户编号。为此,我使用了代码中定义的setCustomerNo()函数。
问题是setCustomerNo()函数内部的while循环无限运行,甚至在文件结束后仍会读取。
请帮助我解决此问题。
我尝试替换:
但以上所有替代方法都不适合我。
#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,以此类推,直到文件中存储的结构。最后返回最后更新的结构。
答案 0 :(得分:1)
您绝对不希望您的循环测试feof(fp)
(实际上就是practically never right),因为如果发生循环,feof(fp)
在结尾处总是为false,所以循环永远不会结束。为什么? fseek
联机帮助页将其说明如下:
成功调用
fseek()
函数将清除流的文件结束指示符。
无论如何,如果您考虑一下,您想在fread
报告没有数据时完全终止循环。您当然不希望处理fread
尚未读取的不存在的数据。因此,即使feof(fp)
实际上返回了一个有用的值,在处理可能的未读数据之后测试是否存在EOF也不对。
其他一些注意事项:
最好使用ftell
来调用read
之前的读取光标,然后fseek
指向保存的点。这样就避免了很多极端情况,并且可以轻松升级以使用更通用的fseeko/ftello
函数,该函数可以正常处理大文件。 (或者,您可以直接使用fseeko
和ftello
。
考虑一下如果最后一个read
是不完整的,您想做什么。当然,如果您始终创建固定长度的记录,则“不可能发生”。但是由于某种原因或其他原因,所有“不可能发生”的事情最终都会发生。最好处理它。