初识文件尾(EOF)


文件尾(EOF,End Of File) 是一个宏常量,表示文件或字符串的尾部。其真值表如下:

if EOF

yes

no

default

value

1

0

-1

当前位置如果是文件末尾,则返回1(true),否则返回0(false),默认值为-1。
通过C++输入工具和操作系统的协同工作,可以使程序得知何时停止向输入队列获取数据。

1. 引导

下面的代码作用是获取字符串输入,并将获取的字符串输出,同时统计所获取字符串的长度。

#include<iostream>

int main ()
{
    using namespace std;
    char ch;
    int count = 0;

    cout << "Enter characters; enter # to quit:\n";
    cin.get(ch); // 接收输入缓存区中的第一个字符
    while(ch != '#') 
    {
        cout << ch;
        ++count;
        cin.get(ch);// 更新字符
    }
    cout << endl << count << " characters read \n";
    return 0;
}

此程序通过键盘手动输入'#'符号来让程序停止获取输入。但这么做的缺点是'#'或其他用来表示输入结尾的符号本身就是要输入的字符,从文件中获取输入更能体现到这一点。利用检查文件尾可以避免这个问题。

1.1 输入缓冲区

程序在获取输入时并不是直接将目标输入导入程序中,而是操作系统将目标内容暂存在输入缓存区(Input Cache)中,程序再从输入缓存区获取内容;目标内容可以来自键盘输入、文件或是来自终端的输出重定向:

不少操作系统的终端都允许通过键盘来模拟文件尾的条件:

  • Unix:光标在行首处按下Ctrl + D

  • Windows:光标在任意位置按下Ctrl + Z + Enter

1.2 检索EOF的函数

C++中,通常使用cin对象来对文本进行输入、输出操作。当cin对象检测到EOF后,cin将俩位(eofbit和failbit)都设置为1,他们分别通过成员函数eof()、fail() 查看。如果检测到EOF,cin.eof()将返回true,否则返回false。如果eofbit 或failbit被设置为1,则cin.fail()返回true,否则返回false,注意:eof()和fail()方法报告最近读取的结果。

2. 正文

了解了上文的场景和相关知识后,下面是上文程序的改进,假设代码编译完成后程可执行文件名为textin.exe

//textin.exe
#include<iostream>

int main ()
{
    using namespace std;
    char ch;
    int count = 0;
    cin.get(ch);
    while (cin.fail() == false) // 利用EOF
    {
        cout << ch;
        ++count;
        cin.get(ch);
    }

    cout << endl << count << " characters read \n";
    return 0;
}

相比与之前的程序,此程序只改变了第九行while的判定条件,当接收到EOF后跳出循环结算字符串长度。 程序运行流程如下:

输入:test

  • 按下回车键后,系统将test载入输入缓冲区,此时程序运行至第八行。

  • 第八行语句将第一个字符(t)读入ch,由于t后还有字符,所以fail()返回false。

  • 第九行while判定条件符合,进入循环。

  • 第13行语句继续将t后一个字符e读入ch,程序返回第9行进行判定。同上一次判定一样,进入循环;如此直至13行将最后一个t读入ch,完成最后一次循环。

  • 此时输入缓冲区已空,由于我们没有通过键盘模拟文件尾,故13行语句一直等待输入缓冲区内添加新字符。

  • 当我们按下Ctrl + Z + Enter,13行语句扑捉到EOF,fail返回true,while循环条件不符,程序跳出循环执行第16行语句。

当从文件读入时,系统会在文本文件末尾自动添加EOF,因此此程序可以用来显示文本文件的内容并统计文件中文本的长度。这里需要用到命令行 中的输出重定向< 它将右边的输出当成左边的输入,例如:textin.exe < test.txt,它的效果即是将test.txt文件中的内容作为输出,当作 textin.exe程序的输入。

2.1 EOF结束输入

在cin对象检测到EOF,并将两个标记设置(eofbit, failbit)后,cin将不再读取输入。再此调用cin也不管用。这么设计的原因是当面对来自文件的输入时,程序不应该读取超出文件尾的内容。但是对于键盘输入,有可能使用EOF来结束循环,并在这之后还需要读取其他输入的,应该用cin.clear()来清除EOF标记、


本文章使用limfx的vscode插件快速发布