How to get the line number from a file in C++?

后端 未结 4 1421
借酒劲吻你
借酒劲吻你 2021-02-02 01:15

What would be the best way to get the line number of the current line in a file that I have opened with a ifstream? So I am reading in the data and I need to store

相关标签:
4条回答
  • 2021-02-02 01:36

    Use std::getline to read each line in one by one. Keep an integer indicating the number of lines you have read: initialize it to zero and each time you call std::getline and it succeeds, increment it.

    0 讨论(0)
  • 2021-02-02 01:46

    An inefficient but dead simple way is to have a function that given a stream, it counts the new line characters from the beginning of the stream to the current position.

    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;
    }
    

    In some code I am working on, I am only interested to know the line number if invalid input is encountered, in which case import is aborted immediately. Since the function is called only once the inefficiency is not really a problem.

    The following is a full example:

    #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;
    }
    
    0 讨论(0)
  • 2021-02-02 01:50

    If you don't want to limit yourself to std::getline, then you could use class derived from std::streambuf, and which keeps track of the current line number:

    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();
    

    Here is a sample implementation of 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
    };
    
    0 讨论(0)
  • 2021-02-02 01:51

    From an ifstream point of view there is no line number. If you read in the file line by line, then you just have to keep track of it yourself.

    0 讨论(0)
提交回复
热议问题