如何使用EOF在C语言中运行文本文件?

How to use EOF to run through a text file in C?

提问人:Tyler Treat 提问时间:12/3/2009 最后编辑:Ciro Santilli OurBigBook.comTyler Treat 更新时间:1/20/2020 访问量:327986

问:

我有一个文本文件,每行都有字符串。我想为文本文件中的每一行增加一个数字,但是当它到达文件末尾时,它显然需要停止。我尝试对EOF进行一些研究,但无法真正了解如何正确使用它。

我假设我需要一个 while 循环,但我不确定该怎么做。

C 文件 EOF

评论


答:

14赞 CB Bailey 12/3/2009 #1

一个可能的 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.
        */
    }
}

现在,我会忽略类似的功能。经验表明,在错误的时间调用它并两次处理某些东西,认为 eof 尚未达到,这太容易了。feof

要避免的陷阱:用于 c 的类型。 将下一个字符强制转换为 AN 返回,然后返回到 .这意味着在大多数 [理智] 平台上,中的值和有效的 “” 值不会重叠,因此您永远不会意外检测到 'normal' 。chargetcharunsigned charintEOFcharcEOFchar

评论

0赞 streetparade 12/3/2009
看我的答案 我定义了一个 EOF
1赞 CB Bailey 12/3/2009
@streetparade:效果如何?
0赞 caf 12/3/2009
有效的字符值 from 不能与任何符合要求的平台上重叠,因为返回 的字符在 (因此是非负数) 的范围内,并且必须为负数。getcharEOFgetcharunsigned intEOF
0赞 CB Bailey 12/3/2009
@caf:我就是这么想的,直到有人向我指出,有 32 个字符和 32 个整数的平台。这意味着 char -> unsigned char -> int 最终可能为负数。因此是“[理智]”。
0赞 caf 12/3/2009
哦,是的,还有关于忽略的好建议 - 根据我的经验,使用该函数几乎总是表明存在错误。在 99% 的情况下,测试最近输入函数调用的返回值就足够且正确。feof
109赞 John Bode 12/3/2009 #2

检测 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

检查输入调用的结果是否符合上述适当条件,然后调用以确定结果是由于命中 EOF 还是其他一些错误造成的。feof()

用: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);
  ...
}

此表单的工作方式与人们想象的不同,因为在您尝试读取文件末尾之前不会返回 true。结果,循环执行一次太多次,这可能会也可能不会给您带来一些悲伤。feof()

评论

1赞 chux - Reinstate Monica 11/7/2015
很好,但这个流行答案的一些建议:1)“函数:EOF结果或错误:成功转换次数少于预期”等同于输入“错误”与格式转换失败。IMO不是正确的分组。建议另一列OTOH,这是一个复杂的功能:2)拼写检查,3)建议“坏代码”,对示例进行评论。fscanf()while(!feof(stream))
0赞 Nematollah Zarmehi 6/5/2014 #3

您应该在从文件读取后检查 EOF。

fscanf_s                   // read from file
while(condition)           // check EOF
{
   fscanf_s               // read from file
}
0赞 valerinho 1/20/2020 #4

我建议你使用 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);