如何在 C 程序中读取文本文件的最后一行?

How do I read the last line of a text file in a C program?

我正在尝试学习 C 语言,基本上我想做的是读取一个文件并将其放入我创建的结构中,然后我将用该结构做其他事情,但我想先通过第一部分。假设我有一个名为 captains.txt 的文本文件,内容为:

picard 95
janeway 90
pike 15

(注意最后一行就是'pike 15')

所以我创建了一个这样的程序:

#include <stdio.h>
#include <stdlib.h> //for exit()
#include <string.h>
#include <ctype.h>

struct captain
{
    char capName[10];
    int number;

};
typedef struct captain captain;

int main()
    {

        FILE* file = fopen("captain.txt","r");
        if (file == NULL)
        {
            printf("\nerror opening file");
            exit(1);
        }

        else{
            printf("\nfile is opened");
        }

        char buffer[50];
        fgets(buffer,50,file);

        while (!feof(file))
        {
            captain c;
            sscanf(buffer, "%s %d", &c.capName, &c.number);
            printf("\nc captain is: %s %d", c.capName, c.number);
            fgets(buffer,50,file);
        }
        fclose(file);

        return 0;
}

我的控制台上的输出是

file is opened
c captain is: picard 95
c captain is: janeway 90
Process returned 0 (0x0)   execution time : 0.006 s
Press any key to continue.

因此派克船长在 space 中不见了......几乎是字面意思,因为当我向文本文件添加新行时,它变成了这样:

picard 95
janeway 90
pike 15

(注意'pike 15'后的换行符)

然后我的输出就正确了。所以我知道我的程序没有考虑文件末尾缺少换行符的问题......那么我该如何解决这个问题?

比较这两个程序,一个(误)使用 feof() 和一个根本不使用它。第一个与问题中的代码密切相关——它忽略了 fgets() 中的 return 值而不利于它。第二个只测试来自 fgets() 的 return 值;它不需要使用 feof().

eof53.c

#include <stdio.H>

int main(void)
{
    char buffer[256];

    fgets(buffer, sizeof(buffer), stdin);
    while (!feof(stdin))
    {
        printf("[%s]\n", buffer);
        fgets(buffer, sizeof(buffer), stdin);
    }
    return 0;
}

eof71.c

#include <stdio.H>

int main(void)
{
    char buffer[256];

    while (fgets(buffer, sizeof(buffer), stdin) != NULL)
        printf("[%s]\n", buffer);
    return 0;
}

给定一个包含 3 个字节的数据文件 abc — 0x41 ('A')、0x42 ('B')、0x43 ('C') 并且没有换行符,我得到结果如下:

$ eof53 < abc
$ eof71 < abc
[ABC]
$

这是在 MacOS Big Sur 11.6.6 上测试的。

请注意,fgets() 在读取(唯一的)不完整行时不会报告 EOF(通过 return 空指针),但根据经验,feof() 确实会报告 EOF — 正确, 由于文件输入已经结束,即使 fgets() 做了 return 一个字符串(但不是一行)数据。

如规范问答 while (!feof(file)) is always wrong! 中所述,使用 feof() 而不是测试 I/O 函数中的 return 值会导致错误结果。