繁体   English   中英

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

[英]Reading from file and exiting loop using feof()

该链接说明了为什么feof()不好用作循环的退出指示器。

不安全==>在while中有feof()检查,而while中有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

如果您的文本文件在文本的最后一行之后没有换行符结束,则testUnsafe()函数将在读取最后一行时到达文件结尾,并产生您显示的三行输出。

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

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

我尝试了两个示例,但结果却不同。 函数testUnsafe()将文件的最后一行打印了两次。 有两个原因。

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

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

我将您的函数复制到了我的测试程序中

#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

基本上,要阅读所有行,您必须使用类似的算法。 如果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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM