使用feof()从文件读取和退出循环

时间:2014-12-13 20:09:27

标签: c file-io fgets feof

This link讲述为什么feof()作为循环的退出指示符是一件坏事。

不安全==>在那里进行feof()检查,并在其中进行fgets()

安全==>在{while}本身进行fgets()!=NULL检查。

我应该看到不安全的代码执行额外的while循环迭代,但两者都执行相同(和正确)的循环次数。有人可以帮我理解这里发生了什么吗?

编辑:链接实际上确实说明了为什么会发生这种情况,但下面的正确答案让我理解我正在阅读的内容。我的档案中没有' \ n'在最后一行,所以得到了相同的结果。

这是文件内容:

abcd
efgh
ijkl

以下代码:

void testUnsafe(void) {
    FILE *f;
    char buf[20];
    f = fopen("fil.txt", "r");
    while (!feof(f)) {
        fgets(buf, 20, f);
        if (buf[strlen(buf) - 1] == '\n') //cleaner
            buf[strlen(buf) - 1] = '\0';
        printf("%s , %d\n", buf, strlen(buf));
    }
    fclose(f);
}

void testSafe(void) {
    FILE *f;
    char buf[20];
    f = fopen("fil.txt", "r");
    while (fgets(buf, 20, f) != NULL) {
        if (buf[strlen(buf) - 1] == '\n') //cleaner
            buf[strlen(buf) - 1] = '\0';
        printf("%s , %d\n", buf, strlen(buf));
    }
    fclose(f);
}

输出是:

******unsafe test********
abcd , 4
efgh , 4
ijkl , 4
********safe test********
abcd , 4
efgh , 4
ijkl , 4

3 个答案:

答案 0 :(得分:3)

如果您的文本文件在最后一行文本后结束而没有换行符,则testUnsafe()函数在读取最后一行时将到达文件结尾,并生成三个你已经展示的输出线。

如果您的文本文件 在最后一行文本后面有换行符,则该函数将读取最后一行,包括换行符,不带到达结束行文件。当它再次进入while()循环时,它会读取零个字符,设置文件结束标志,并输出最后一行仍在缓冲区中的最后一行。

while (!feof(f))构造本身并不安全 。它忽略了检查不安全的fgets()的返回值。

答案 1 :(得分:2)

我尝试了你的两个例子,并得到了不同的结果。函数testUnsafe()两次打印了我文件的最后一行。这有两个原因。

  1. 如果读取操作已尝试读取文件末尾,则feof()函数返回非零值。

  2. 函数testUnsafe()不检查fgets()的返回值,因此在达到feof()条件之前重复先前读取的字符串。

  3. 我将你的功能复制到我的测试程序中

    #include <stdio.h>
    #include <string.h>
    
    void testUnsafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (!feof(f)) {
            fgets(buf, 20, f);
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    void testSafe(void) {
        FILE *f;
        char buf[20];
        f = fopen("fil.txt", "r");
        while (fgets(buf, 20, f) != NULL) {
            if (buf[strlen(buf) - 1] == '\n') //cleaner
                buf[strlen(buf) - 1] = '\0';
            printf("%s , %d\n", buf, strlen(buf));
        }
        fclose(f);
    }
    
    int main()
    {
        testUnsafe();
        printf ("\n\n");
        testSafe();
        return 0;
    }
    

    测试文件:

    Line 1
    Line 2
    Line 3
    

    testUnsafe()的输出:

    Line 1 , 6
    Line 2 , 6
    Line 3 , 6
    Line 3 , 6
    

    testSafe()的输出:

    Line 1 , 6
    Line 2 , 6
    Line 3 , 6
    

答案 2 :(得分:0)

基本上,要阅读所有行,您必须使用类似的算法。 如果ou在文件末尾没有换行符,则一定要加载所有行。

这里的例外是最后一行不确定结尾处是否有LF。

除了检查缓冲区溢出以优化内存使用以外,还可以调用realloc()修剪缓冲区,然后再将其添加到数组中。

buffer = (char*)malloc(bufferSize);
while(fgets(buffer, bufferSize, file) != NULL) {
    //here store your pointer in array...
    buffer = (char*)malloc(bufferSize);
};
free(buffer);