如何在使用istream_iterator时忽略最后一个空行

How to ignore final blank line when using istream_iterator

本文关键字:最后一个 iterator istream      更新时间:2023-10-16

假设我有一个2D点的简单文本文件,如下所示:

10
0.000   0.010
0.000   0.260
0.000   0.510
0.000   0.760
0.000   1.010
0.000   1.260
0.000   1.510
0.000   1.760
0.000   2.010
0.000   2.260
// Blank line here

我使用一个简单的IO结构:

template <typename T>
struct point
{
    point (T x = 0, T y = 0) : x (x), y (y) {}
    T x ;
    T y ;
    friend std::istream& operator>> (std::istream &is, point &p) {
        is >> p.x >> p.y ;
        return is ;
    }
};

我最初的代码是:

int main (void)
{
    std::string strFile = "Points.txt" ;
    std::ifstream file ;
    file.exceptions (std::ios::failbit | std::ios::badbit) ;
    std::vector <point <double> > vec ;
    try {
        file.open (strFile) ;
        int nPoints = 0 ;
        file >> nPoints ;
        for (int n = 0; n < nPoints; ++n) {
            point <double> p ;
            file >> p ;
            vec.push_back (p) ;
        }
    }
    catch (std::ios_base::failure &e) {
        std::cerr << e.what () << "n" ;
        return 1 ;
    }
    return 0 ;
}

这很好,但本着没有原始循环的精神,我想去掉for循环。

这是我的新代码:

int main (void)
{
    std::string strFile = "Points.txt" ;
    std::ifstream file ;
    file.exceptions (std::ios::failbit | std::ios::badbit) ;
    std::vector <point <double> > vec ;
    try {
        file.open (strFile) ;
        int nPoints = 0 ;
        file >> nPoints ;
        std::copy (
            std::istream_iterator <point <double> > (file), 
            std::istream_iterator <point <double> > (), 
            std::back_inserter (vec)
        ) ;
    }
    catch (std::ios_base::failure &e) {
        std::cerr << e.what () << "n" ;
        return 1 ;
    }
    return 0 ;
}

一切都复制得很好,但不幸的是,读取最后一行空行会导致设置失败位。

我唯一能想到的解决办法是有点难看。我可以:

  • point::operator>>()函数中放入try-catch子句
  • 检查catch子句中已存在的vec.size()

有没有一种优雅的方法可以忽略最后一行空白?

更改

    std::copy (
        std::istream_iterator <point <double> > (file), 
        std::istream_iterator <point <double> > (), 
        std::back_inserter (vec)
    ) ;

    std::copy_n (
        std::istream_iterator <point <double> > (file), 
        nPoints, 
        std::back_inserter (vec)
    ) ;