使用 fgets 达到 EOF

Posted

技术标签:

【中文标题】使用 fgets 达到 EOF【英文标题】:Reaching EOF with fgets 【发布时间】:2013-03-07 05:15:48 【问题描述】:

我正在编写一个执行某些身份验证操作的函数。我有一个包含所有user_id:password:flag 夫妇的文件,其结构如下:

Users.txt

user_123:a1b2:0 user_124:a2b1:1 user_125:a2b2:2

这是代码:

int main()
    /*...*/

    /*user_id, password retrieving*/
    USRPSW* p = malloc(sizeof(USRPSW));
    if(p == NULL)
        fprintf(stderr, "Dynamic alloc error\n");
        exit(EXIT_FAILURE);
    
    memset((void*)p, 0, sizeof(USRPSW));

    if(usr_psw_read(acc_sock_ds, p->user_id, USR_SIZE) <= 0)
        printf("Failed read: connection with %s aborted.\n",
                 inet_ntoa(client_addr.sin_addr));
        close(acc_sock_ds);
        continue;
    

    if(usr_psw_read(acc_sock_ds, p->password, PSW_SIZE) <= 0)
        printf("Failed read: connection with %s aborted.\n",
                 inet_ntoa(client_addr.sin_addr));
        close(acc_sock_ds);
        continue;
    

    /*Authentication through user_id, password*/
    FILE *fd;
    fd = fopen(USERSFILE, "r");
    if(fd == NULL)
        fprintf(stderr, "Users file opening error\n");
        exit(EXIT_FAILURE);
    

    char *usr_psw_line = malloc(USR_SIZE+PSW_SIZE+3+1);
    if(usr_psw_line == NULL)
        fprintf(stderr, "Dynamic alloc error\n");
        exit(EXIT_FAILURE);
    

    while(1)

        memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
        fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd);
        printf("%s\n", usr_psw_line);
        fseek(fd, 1, SEEK_CUR);


        /*EOF management*/
        /*usr_id - password matching checking */

       
/*...*/    

如何管理 EOF 到达?我看到当达到 EOF 时 fgets 不再编辑 usr_psw_line 但既不返回 NULL 指针。如果达到 EOF,则意味着在用户文件中找不到匹配项并且循环中断。

谁能给我一些提示或建议?

【问题讨论】:

如果在没有读取任何字符的情况下到达文件末尾,fgets 必须返回NULL。无论如何,您可以在 fgets 没有阅读任何内容之后检查 feof(fd) 恐怕没有设置EOF。我只写了一个里面有记录的文件。我还应该明确设置EOF吗?你是怎么做到的? 不就是读到文件尾吗?您不设置 EOF,如果到达文件末尾,则下一次尝试读取文件将在 *fd 中设置标志,因此如果一切正常,feof(fd) 将返回 true。如果一切都无法正常工作,嗯。 EOF 是一个条件,而不是流的一部分。想象溪流是水龙头里的水。当您打开水龙头直到它耗尽时,您是否会得到更多水(另一种颜色?)以表示没有更多水了? 【参考方案1】:

fgets() 在到达文件结尾或错误条件时返回一个空指针。

EOF 是一个宏,它指定某些其他函数在类似条件下返回的值;它不仅仅是短语“文件结尾”的缩写。)

您忽略了fgets() 返回的结果。不要那样做。

请注意,仅检查 feof(fd) 不会满足您的要求。如果您已到达文件末尾,feof() 将返回 true 结果。如果您遇到错误,feof() 仍然返回 false,如果您使用 feof() 来决定何时完成,您就会陷入无限循环。并且直到 您未能读取输入后它才会返回 true。

大多数 C 输入函数都会返回一些特殊值,以表明没有更多可读取的内容。对于fgets(),它是NULL,对于fgetc(),它是EOF,等等。如果您愿意,您可以在之后致电feof() 和/或ferror() 来确定为什么没有什么可阅读的了。

【讨论】:

(笑着说)我之前的回答不是说的吗? @SteveValliere 或多或少,但我试图更明确地了解基本概念。【参考方案2】:

你可能想在你的循环中尝试这样的事情:

while(1)

    memset((void*)usr_psw_line, 0, sizeof(USR_SIZE+PSW_SIZE+3+1));
    if( !fgets(usr_psw_line, USR_SIZE+PSW_SIZE+3+1, fd)
     || ferror( fd ) || feof( fd ) )
    
        break;
    
    printf("%s\n", usr_psw_line);
    fseek(fd, 1, SEEK_CUR);

    /*EOF management*/
    /*usr_id - password matching checking */


使用额外的代码,如果fgets 返回 NULL(没有更多数据要读取)或者如果您读取了 EOF 标记或文件上有任何错误,则循环将终止。我敢肯定这是矫枉过正,但这些测试一直对我有用。

【讨论】:

最好 (IMO) 使用 while (fgets(usr_psw_line, sizeof(usr_psw_line), fd) != 0) 作为循环条件。在读取之前确实不需要将内存归零。并且在那里使用ferror()feof() 进行测试没有任何好处(因为如果从fgets() 返回的测试返回NULL,它们只会评估为true;因此,它们永远不会导致循环退出)。跨度> 同意。我试图尽可能多地保留原始代码,以便直接回答问题的部分清楚。但我完全按照你在我所有的文件读取循环中描述的那样做。 @chux:我的论点是基于如果在调用fgets() 时设置了错误标志,fgets() 必须失败的命题。但是,我实际上无法在标准中找到强制执行此操作的措辞,尽管我会惊讶地发现没有那样做的实现。如果您跟踪流的状态,除非您使用clearerr(),否则您将不会在失败后使用它。有一个难以置信的边缘案例可用。测试feof() 毫无意义。我坚持我对日常使用的观察。如果我担心流的错误状态,我会在函数入口处使用ferror() 示例中的代码“sizeof(USR_SIZE+PSW_SIZE+3+1)”总是计算整数的大小 - 在许多现代机器上,它总是 4,无论USR_SIZE 和 PSW_SIZE——“sizeof(42)”(或任何其他较小的数字)将返回相同的值。我猜封闭的“sizeof(...)”是一个错误。无论如何,将整个缓冲区归零是多余的——如果有人怀疑 fgets() 的行为——一个基于 C 字符串的函数——那么 "usr_psw_line[0] = '\0';"就足够了。 如果要使用 feof() 和/或 ferror(),它们可能应该在调用 fgets() 之前调用 - 以确定给定文件是否为 已经处于先前活动的 EOF 或错误状态 - 或 fgets() 返回 NULL,以确定 fgets() 返回 NULL 的原因。在当前的形式中,他们除了误导查看代码的人外,几乎没有做任何事情。

以上是关于使用 fgets 达到 EOF的主要内容,如果未能解决你的问题,请参考以下文章

试图理解 fgets()

在不移动文件指针的情况下检查文件指针是不是已达到 EOF?

C语言 fgets 从文件中读取一个字符串

请教peek()与eof()的用法

求教c语言中fgets的用法

fsockopen用feof读取http响应内容的一些问题