C++正确读取文件最后一行

一 问题

使用C++ ifstream来读取文件时,发现在读到文件结尾时会多读一行。测试代码如下,

#include <iostream>
#include <fstream>
#include <string>

int main(void)
{
    std::ifstream inf("data.txt");
    if (!inf) {
        std::cerr << "open data.txt fail\n";
        return 1;
    }

    std::string oneline;
    while (inf.eof() == false) {  // 问题点
        std::getline(inf, oneline);
		std::cout << oneline << "\n";
    }

    return 0;
}

data.txt内容如下,
这里写图片描述
输出如下,多读了一行,为空。
这里写图片描述


二 解决办法

方法1

直接判断std::getline()的返回值,

#include <iostream>
#include <fstream>
#include <string>

int main(void)
{
    std::ifstream inf("data.txt");
    if (!inf) {
        std::cerr << "open data.txt fail\n";
        return 1;
    }

    std::string oneline;
    while (std::getline(inf, oneline)) { 
		std::cout << oneline << "\n";
    }

    return 0;
}

方法2

使用文件流的peek()方法来代替eof()方法,如下,

#include <iostream>
#include <fstream>
#include <string>

int main(void)
{
    std::ifstream inf("data.txt");
    if (!inf) {
        std::cerr << "open data.txt fail\n";
        return 1;
    }

    std::string oneline;
    while (inf.peek() != EOF) { // 关键行
        std::getline(inf, oneline);
		std::cout << oneline << "\n";
    }

    return 0;
}

输出如下,
这里写图片描述
可见最后一行得到了正确的处理。

方法3

先调用std::getline()去读取,然后先判断eof()再决定是否打印,

#include <iostream>
#include <fstream>
#include <string>

int main(void)
{
    std::ifstream inf("data.txt");
    if (!inf) {
        std::cerr << "open data.txt fail\n";
        return 1;
    }

    std::string oneline;
    while (true)
    {
        std::getline(inf, oneline);
        if (inf.eof() == true)
            break;
        std::cout << oneline << "\n";
    }

    return 0;
}

三 原因分析

《C++ primer 5th》17.5.2节对文件流的peek()方法描述如下,

peek返回输入流中下一个字符的副本,但不会将它从流中删除。peek返回的值仍然留在流中。

所以,通过peek()来提前预判下一个字符是不是文件结束符EOF,就可以让我们提前知道文件流是否已经到了结尾,就可以正确结束输入。

为什么eof()方法不行呢?下面来分析下,上面用于测试的data.txt,其实际结构如下,
在这里插入图片描述
文件最后会有个EOF(End Of File)表示文件内容的结束。

当使用std::getline()读取完4444后,此时如果使用peek(),则返回值是EOF,而peek()方法的功能是预判下一个字符,由此可以知道std::getline()读完4444后,文件句柄的位置并不在EOF处,而是在EOF之前的那个字符位置上,此时使用eof()方法会返回false,然后调用std::getline()去读取EOF,就会导致错误,参数oneline就会变成空字符串,所以就会多打印一个空行。

如果有写的不对的地方,希望能留言指正,谢谢阅读。

评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值