Reading a whole file into a string, with ifstream

Started by
6 comments, last by Fruny 18 years, 5 months ago
Very quick question. I'm starting to use C++ ifstreams for the first time having used C-style file IO functions for the last 5+ years. I want to read an entire text file into a string, and I tried using simply: ifstream theFile( "foo.txt", ios_base::in ); string theString; theFile >> theString; ...but this only reads in one line at a time, like fgets does. How can I read the whole file into the string? Thanks.
Advertisement
You can try istreambuf_iterators. ex:
  std::ifstream ifs("filename.txt");    std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

Mind the extra parenthesis in the str declaration, it's necessary for correct parsing.
Works a charm, thanks.
I think you can use the ifstream::read function. Like this:

std::ifstream file("foo.txt", std::ios_base::in|std::ios_base::ate);long file_length = file.tellg()file.seekg(0, std::ios_base::beg);file.clear();char *string = new char[file_length];file.read(string, file_length);


Edit: Oh, didn't see SiCrane's post. That's a really nice way of doing it!
OK, so SiCrane's suggestion worked perfectly. The next thing I'm wondering is, why. :-) Intellisense doesn't seem to want to tell me anything about what it's doing (presumably it's getting confused by std::string being a typedef, or something).

All I can figure out by looking at it directly is that it's presumably using a constructor for the string that takes a (first,last) pair of iterators? But then, I'm not sure why the first iterator must be in brackets, or how the last iterator works at all without any values... I'm intrigued. Could you please explain? Thanks!

C++ is something of an exploration for me having been so ingrained in C, it's succinct code like this that makes it appealing, but I feel the need to understand it, not just use it! :-)
Yes, it's a string constructor that takes an input iterator pair. The first input iterator is an istreambuf_iterator initialized with the stream. The second input iterator is an istreambuf_iterator is default constructed. A default constructed istreambuf_iterator returns equal to another istreambuf_iterator that has exhausted the input from the streambuf it was reading from. So the constructor reads from the first istreambuf_iterator until it runs out of data.

The first argument needs to go in parenthesis otherwise the compiler will parse the string declaration as a function declaration. Specifically a function that returns a string, called str that takes as a first argument a istreambuf_iterator<char> called ifs and as a second argument an istreambuf_iterator<char> that is unnamed. Technically you can also wrap the second argument in parenthesis instead, but usually when you do it, you wrap the first one.
That's very clever... I like it!
Quote:Original post by SunTzu
All I can figure out by looking at it directly is that it's presumably using a constructor for the string that takes a (first,last) pair of iterators?


Exactly.

Quote:But then, I'm not sure why the first iterator must be in brackets


It's a case of C++'s "most vexing parse" (Scott Meyer's Effective STL, Item 6): anything that can be parsed as a declaration is a declaration.

The statement: std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());

Is of the form: type new_symbol( (type(symbol)), type);

Without the extra ( ), it would be type new_symbol( type(symbol), type);

Which is equivalent to type new_symbol( type symbol, type);

That is, a function declaration, with one named and one unnamed parameter, rather than a variable definition

Quote:or how the last iterator works at all without any values...


That iterator class has a default constructor. Comparing a stream iterator to the default-constructed iterator is equivalent to testing if the stream has reached EOF. There is no real need for that end-of-file marker to be associated with any specific stream, so the library designers picked the default constructor to generate it. Alternatives would be clumsier, involving a static member function - and probably a pair of them, for symmetry. Or a function returning a pair of iterators (which is a valid approach, see Boost).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement