Sign in to follow this  
SunTzu

Reading a whole file into a string, with ifstream

Recommended Posts

SunTzu    286
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.

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

Share this post


Link to post
Share on other sites
James Trotter    432
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!

Share this post


Link to post
Share on other sites
SunTzu    286
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! :-)

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

Share this post


Link to post
Share on other sites
Fruny    1658
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).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this