puppydog
puppydog

Reputation: 385

Weird behavior with ifstreams and rdbuf()

I've noticed that using .rdbuf() on an ifstream seems to change it somehow. The following code should show the problem.

#include <fstream>
#include <iostream>

using namespace std;

int main(int argc, const char * argv[]) {
    ifstream ifs("Sample.csv");
    cout << "Reading buffer: " << endl;
    cout << ifs.rdbuf(); // Outputs buffer as expected
    cout << "Reading buffer again: " << endl;
    cout << ifs.rdbuf(); // Returns nothing

    return 0;
}

The reason this is bothering me is that I'm currently trying to copy the contents of one text file into another using ofstream ofs; ofs << ifs.rdbuf(). This works fine but makes reading from ifs using getline(ifs, str) fail, effectively "breaking" the stream.

Upvotes: 2

Views: 2282

Answers (2)

puppydog
puppydog

Reputation: 385

ifs.rdbuf() returns a pointer to the ifs's corresponding stream buffer object. Sending it to std::cout via << overload pulls information from the stream until the end of the buffer is reached (eof). Calling .rdbuf() again returns "nothing" because there's nothing to read at the end of the buffer. The buffer seek position be explicitly reset to zero by calling ifs.seekg (0);.

Upvotes: 3

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385264

This isn't particularly "weird"; it's the same stream behaviour you see every day. rdbuf isn't like std::stringstream::str() and it isn't magic — it's a pointer to the buffer, that your cout is then reading from just as you would read from the original stream yourself:

std::stringstream ss("1");
int x;
if (ss >> x)
   cout << x;
if (ss >> x)   // doesn't work a second time; "1" is already extracted
   cout << x;

As your stream is a file stream, you can seek it back to the beginning to start from scratch (which will inherently do the same to its underlying buffer).

Upvotes: 3

Related Questions