如何从C ++文件中获取行号?

时间:2011-01-27 05:43:41

标签: c++ line fstream

在我使用ifstream打开的文件中获取当前行的行号的最佳方法是什么?所以我正在读取数据,我需要存储它所在的行号,这样如果数据与规格不匹配,我可以稍后显示它。

4 个答案:

答案 0 :(得分:11)

如果您 希望将自己限制为std::getline,那么您可以使用从std::streambuf派生的类,并跟踪当前的行号:< / p>

class CountingStreamBuffer : public std::streambuf { /* see below */ };

// open file
std::ifstream file("somefile.txt");

// "pipe" through counting stream buffer
CountingStreamBuffer cntstreambuf(file.rdbuf());
std::istream is(&cntstreambuf);

// sample usage
is >> x >> y >> z;
cout << "At line " << cntstreambuf.lineNumber();
std::getline(is, str);
cout << "At line " << cntstreambuf.lineNumber();

以下是CountingStreamBuffer的示例实现:

#include <streambuf>

class CountingStreamBuffer : public std::streambuf
{
public:
    // constructor
    CountingStreamBuffer(std::streambuf* sbuf) : 
        streamBuf_(sbuf), 
        lineNumber_(1),
        lastLineNumber_(1),
        column_(0),
        prevColumn_(static_cast<unsigned int>(-1)),
        filePos_(0) 
    {
    }

    // Get current line number
    unsigned int        lineNumber() const  { return lineNumber_; }

    // Get line number of previously read character
    unsigned int        prevLineNumber() const { return lastLineNumber_; }

    // Get current column
    unsigned int        column() const   { return column_; }

    // Get file position
    std::streamsize     filepos() const { return filePos_; }

protected:
    CountingStreamBuffer(const CountingStreamBuffer&);
    CountingStreamBuffer& operator=(const CountingStreamBuffer&);

    // extract next character from stream w/o advancing read pos
    std::streambuf::int_type underflow() 
    { 
        return streamBuf_->sgetc(); 
    }

    // extract next character from stream
    std::streambuf::int_type uflow()
    {
        int_type rc = streamBuf_->sbumpc();

        lastLineNumber_ = lineNumber_;
        if (traits_type::eq_int_type(rc, traits_type::to_int_type('\n'))) 
        {
            ++lineNumber_;
            prevColumn_ = column_ + 1;
            column_ = static_cast<unsigned int>(-1);
        }

        ++column_;
        ++filePos_;
        return rc;
    }

    // put back last character
    std::streambuf::int_type pbackfail(std::streambuf::int_type c)
    {
        if (traits_type::eq_int_type(c, traits_type::to_int_type('\n'))) 
        {
            --lineNumber_;
            lastLineNumber_ = lineNumber_;
            column_ = prevColumn_;
            prevColumn_ = 0;
        }

        --column_;
        --filePos_;

        if (c != traits_type::eof())
            return streamBuf_->sputbackc(traits_type::to_char_type(c));  
        else 
            return streamBuf_->sungetc();
    }

    // change position by offset, according to way and mode  
    virtual std::ios::pos_type seekoff(std::ios::off_type pos, 
                                  std::ios_base::seekdir dir, 
                                  std::ios_base::openmode mode)
    {
        if (dir == std::ios_base::beg 
         && pos == static_cast<std::ios::off_type>(0))
        {
            lastLineNumber_ = 1;
            lineNumber_ = 1;
            column_ = 0;
            prevColumn_ = static_cast<unsigned int>(-1);
            filePos_ = 0;

            return streamBuf_->pubseekoff(pos, dir, mode);
        }
        else
            return std::streambuf::seekoff(pos, dir, mode);
    }

    // change to specified position, according to mode
    virtual std::ios::pos_type seekpos(std::ios::pos_type pos,
                                  std::ios_base::openmode mode)
    {   
        if (pos == static_cast<std::ios::pos_type>(0))
        {
            lastLineNumber_ = 1;
            lineNumber_ = 1;
            column_ = 0;
            prevColumn_ = static_cast<unsigned int>(-1);
            filePos_ = 0;

            return streamBuf_->pubseekpos(pos, mode);
        }
        else
            return std::streambuf::seekpos(pos, mode);
    }


private:
    std::streambuf*     streamBuf_;     // hosted streambuffer
    unsigned int        lineNumber_;    // current line number
    unsigned int        lastLineNumber_;// line number of last read character
    unsigned int        column_;        // current column
    unsigned int        prevColumn_;    // previous column
    std::streamsize     filePos_;       // file position
};

答案 1 :(得分:10)

从ifstream的角度来看,没有行号。如果你逐行读入文件,那么你只需要自己跟踪它。

答案 2 :(得分:5)

使用std::getline逐行读取每一行。保持一个整数,表示您已读取的行数:将其初始化为零,每次调用std::getline并成功时,将其递增。

答案 3 :(得分:1)

一种低效但简单的简单方法是使用一个给定流的函数,它会计算从流的开头到当前位置的新行字符。

int getCurrentLine(std::istream& is)
{
    int lineCount = 1;
    is.clear();     // need to clear error bits otherwise tellg returns -1.
    auto originalPos = is.tellg();
    if (originalPos < 0) 
        return -1;
    is.seekg(0);
    char c;
    while ((is.tellg() < originalPos) && is.get(c))
    {
        if (c == '\n') ++lineCount;
    }
    return lineCount;
}

在我正在处理的一些代码中,我只想知道遇到无效输入时的行号,在这种情况下导入会立即中止。由于函数只被调用一次,效率低下并不是真正的问题。

以下是一个完整的例子:

#include <iostream>
#include <sstream>


int getCurrentLine(std::istream& is)
{
    int lineCount = 1;
    is.clear();     // need to clear error bits otherwise tellg returns -1.
    auto originalPos = is.tellg();
    if (originalPos < 0) 
        return -1;
    is.seekg(0);
    char c;
    while ((is.tellg() < originalPos) && is.get(c))
    {
        if (c == '\n') ++lineCount;
    }
    return lineCount;
}

void ReadDataFromStream(std::istream& s)
{
    double x, y, z;
    while (!s.fail() && !s.eof())
    {
        s >> x >> y >> z;
        if (!s.fail())
            std::cout << x << "," << y << "," << z << "\n";
    }

    if (s.fail())
        std::cout << "Error at line: " << getCurrentLine(s) << "\n";
    else
        std::cout << "Read until line: " << getCurrentLine(s) << "\n";
}

int main(int argc, char* argv[])
{
    std::stringstream s;
    s << "0.0 0.0 0.0\n";
    s << "1.0 ??? 0.0\n";
    s << "0.0 1.0 0.0\n";
    ReadDataFromStream(s);

    std::stringstream s2;
    s2 << "0.0 0.0 0.0\n";
    s2 << "1.0 0.0 0.0\n";
    s2 << "0.0 1.0 0.0";
    ReadDataFromStream(s2);

    return 0;
}