【发布时间】:2010-12-22 14:25:36
【问题描述】:
我有一个文本文件,每行都有字符串。我想为文本文件中的每一行增加一个数字,但是当它到达文件末尾时,它显然需要停止。我曾尝试对 EOF 进行一些研究,但无法真正理解如何正确使用它。
我假设我需要一个 while 循环,但我不知道该怎么做。
【问题讨论】:
我有一个文本文件,每行都有字符串。我想为文本文件中的每一行增加一个数字,但是当它到达文件末尾时,它显然需要停止。我曾尝试对 EOF 进行一些研究,但无法真正理解如何正确使用它。
我假设我需要一个 while 循环,但我不知道该怎么做。
【问题讨论】:
我建议你使用 fseek-ftell 函数。
FILE *stream = fopen("example.txt", "r");
if(!stream) {
puts("I/O error.\n");
return;
}
fseek(stream, 0, SEEK_END);
long size = ftell(stream);
fseek(stream, 0, SEEK_SET);
while(1) {
if(ftell(stream) == size) {
break;
}
/* INSERT ROUTINE */
}
fclose(stream);
【讨论】:
你应该在读取文件后检查 EOF。
fscanf_s // read from file
while(condition) // check EOF
{
fscanf_s // read from file
}
【讨论】:
如何检测 EOF 取决于您使用什么来读取流:
function result on EOF or error
-------- ----------------------
fgets() NULL
fscanf() number of succesful conversions
less than expected
fgetc() EOF
fread() number of elements read
less than expected
检查输入调用的结果是否符合上述条件,然后调用feof() 以确定结果是由于遇到 EOF 还是其他错误。
使用fgets():
char buffer[BUFFER_SIZE];
while (fgets(buffer, sizeof buffer, stream) != NULL)
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}
使用fscanf():
char buffer[BUFFER_SIZE];
while (fscanf(stream, "%s", buffer) == 1) // expect 1 successful conversion
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}
使用fgetc():
int c;
while ((c = fgetc(stream)) != EOF)
{
// process c
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted the read
}
使用fread():
char buffer[BUFFER_SIZE];
while (fread(buffer, sizeof buffer, 1, stream) == 1) // expecting 1
// element of size
// BUFFER_SIZE
{
// process buffer
}
if (feof(stream))
{
// hit end of file
}
else
{
// some other error interrupted read
}
注意形式都是一样的:检查读操作的结果;如果失败,然后检查 EOF。你会看到很多这样的例子:
while(!feof(stream))
{
fscanf(stream, "%s", buffer);
...
}
这个表单并不像人们想象的那样工作,因为feof() 直到在您尝试读取文件末尾之后才会返回 true。结果,循环执行了太多次,这可能会也可能不会让您感到悲伤。
【讨论】:
fscanf()result on EOF 或错误:成功转换的次数少于预期”将输入“错误”等同于格式转换失败. 不是一个正确的分组 IMO。建议另一列 OTOH 这是一个复杂的功能 2) 拼写检查 3) 建议对 while(!feof(stream)) 示例进行“错误代码”评论。
一个可能的 C 循环是:
#include <stdio.h>
int main()
{
int c;
while ((c = getchar()) != EOF)
{
/*
** Do something with c, such as check against '\n'
** and increment a line counter.
*/
}
}
现在,我会忽略 feof 和类似的功能。经验表明,在错误的时间调用它并在认为尚未达到 eof 的情况下处理两次太容易了。
要避免的陷阱:将char 用于c 的类型。 getchar 将下一个字符转换为unsigned char,然后返回到int。这意味着在大多数 [sane] 平台上,EOF 的值和 c 中的有效“char”值不会重叠,因此您永远不会意外检测到 EOF 的“正常”char .
【讨论】:
getchar 的有效字符值在任何符合标准的平台上永远不会与EOF 重叠,因为getchar 返回的字符在unsigned int 的范围内(因此是非负数),并且EOF 必须是负数。
feof 的好建议——根据我的经验,使用该功能几乎总是表明存在错误。在 99% 的情况下,测试最近一次输入函数调用的返回值就足够且正确。