MrJackV
MrJackV

Reputation: 557

Getting the nth line of a text file in C++

I need to read the nth line of a text file (e.g. textfile.findline(0) would find the first line of the text file loaded with ifstream textfile). Is this possible? I don't need to put the contents of the file in an array/vector, I need to just assign a specific line of the text file to a varible (specifically a int).

P.S. I am looking for the simplest solution that would not require me to use any big external library (e.g. Boost) Thanks in advance.

Upvotes: 8

Views: 18326

Answers (4)

Mooing Duck
Mooing Duck

Reputation: 66961

Armen's solution is the correct answer, but I thought I'd throw out an alternative, based on jweyrich's caching idea. For better or for worse, this reads in the entire file at construction, but only saves the newline positions (doesn't store the entire file, so it plays nice with massive files.) Then you can simply call ReadNthLine, and it will immediately jump to that line, and read in the one line you want. On the other hand, this is only optimal if you want to get only a fraction of the lines at a time, and the line numbers are not known at compile time.

class TextFile {
    std::ifstream file_stream;
    std::vector<std::ifstream::streampos> linebegins;
    TextFile& operator=(TextFile& b) = delete;
public;
    TextFile(std::string filename) 
    :file_stream(filename) 
    {
        //this chunk stolen from Armen's, 
        std::string s;
        //for performance
        s.reserve(some_reasonable_max_line_length); 
        while(file_stream) {
            linebegins.push_back(file_stream.tellg());
            std::getline(file_stream, s);
        }
    }
    TextFile(TextFile&& b) 
    :file_stream(std::move(b.file_stream)), 
    :linebegins(std::move(b.linebegins))
    {}
    TextFile& operator=(TextFile&& b) 
    {
        file_stream = std::move(b.file_stream);
        linebegins = std::move(b.linebegins);
    }
    std::string ReadNthLine(int N) {
        if (N >= linebegins.size()-1)
            throw std::runtime_error("File doesn't have that many lines!");
        std::string s;
        // clear EOF and error flags
        file_stream.clear();
        file_stream.seekg(linebegins[N]);
        std::getline(file_stream, s);
        return s;
    }
};

Upvotes: 2

David Nehme
David Nehme

Reputation: 21597

If you want to read the start of the nth line, you can use stdin::ignore to skip over the first n-1 lines, then read from the next line to assign to the variable.

template<typename T>
void readNthLine(istream& in, int n, T& value) {
  for (int i = 0; i < n-1; ++i) {
    in.ignore(numeric_limits<streamsize>::max(), '\n');
  }
  in >> value;
}

Upvotes: 6

Gian
Gian

Reputation: 13955

It's certainly possible. There are (n-1) '\n' characters preceding the nth line. Read lines until you reach the one you're looking for. You can do this on the fly without storing anything except the current line being considered.

Upvotes: 1

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133102

How about this?

std::string ReadNthLine(const std::string& filename, int N)
{
   std::ifstream in(filename.c_str());

   std::string s;
   //for performance
   s.reserve(some_reasonable_max_line_length);    

   //skip N lines
   for(int i = 0; i < N; ++i)
       std::getline(in, s);

   std::getline(in,s);
   return s; 
}

Upvotes: 8

Related Questions