Reading directly from an std::istream into an std::string
std::string
has a resize
function you could use, or a constructor that'll do the same:
boost::uint16_t len;
is.read((char*)&len, 2);
std::string str(len, '\0');
is.read(&str[0], len);
This is untested, and I don't know if strings are mandated to have contiguous storage.
Read whole ASCII file into C++ std::string
Update: Turns out that this method, while following STL idioms well, is actually surprisingly inefficient! Don't do this with large files. (See: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html)
You can make a streambuf iterator out of the file and initialize the string with it:
#include <string>
#include <fstream>
#include <streambuf>
std::ifstream t("file.txt");
std::string str((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
Not sure where you're getting the t.open("file.txt", "r")
syntax from. As far as I know that's not a method that std::ifstream
has. It looks like you've confused it with C's fopen
.
Edit: Also note the extra parentheses around the first argument to the string constructor. These are essential. They prevent the problem known as the "most vexing parse", which in this case won't actually give you a compile error like it usually does, but will give you interesting (read: wrong) results.
Following KeithB's point in the comments, here's a way to do it that allocates all the memory up front (rather than relying on the string class's automatic reallocation):
#include <string>
#include <fstream>
#include <streambuf>
std::ifstream t("file.txt");
std::string str;
t.seekg(0, std::ios::end);
str.reserve(t.tellg());
t.seekg(0, std::ios::beg);
str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
How to read entire stream into a std::string?
How about
std::istreambuf_iterator<char> eos;
std::string s(std::istreambuf_iterator<char>(stream), eos);
(could be a one-liner if not for MVP)
post-2011 edit, this approach is now spelled
std::string s(std::istreambuf_iterator<char>(stream), {});
How do I read a file in C++ and write contents into a string?
Don't use <<
to append something in a string.
Rather than:
while (getline(shaderFile, line)) {
sourceCode << line;
}
Consider:
while (getline(shaderFile, line)) {
sourceCode += line;
}
Reading formatted input from an istream
Although it isn't a priori obvious there is a relatively simple way to change what a stream considers to be whitespace. The way to do it is to imbue()
the stream with a std::locale
object whose std::ctype<char>
facet is replaced to consider the desired characters as whitespace. imbue()
, locale
, ctype
- huh?!? OK, well, these aren't necessarily the things you use day to day so here is a quick example which set's up std::cin
to use comma and newline characters as spaced:
#include <locale>
template <char S0, char S1>
struct commactype_base {
commactype_base(): table_() {
this->table_[static_cast<unsigned char>(S0)] = std::ctype_base::space;
this->table_[static_cast<unsigned char>(S1)] = std::ctype_base::space;
}
std::ctype<char>::mask table_[std::ctype<char>::table_size];
};
template <char S0, char S1 = S0>
struct ctype:
commactype_base<S0, S1>,
std::ctype<char>
{
ctype(): std::ctype<char>(this->table_, false) {}
};
Actually, this particular implementation of std::ctype<char>
can actually be used to use one or two arbitrary char
s as spaces (a proper C++2011 version would probably allow an arbitrary number of arguments; also, the don't really have to be template argumentss). Anyway, with this in place, just drop the following line at the beginning of your main()
function and you are all set:
std::cin.imbue(std::locale(std::locale(), new ::ctype<',', '\n'>));
Note that this really only considers ,
and \n
as space characters. This also means that no other characters are skipped as whitespace. ... and, of course, a sequence of multiple comma characters is considered to be just one separator rather than possibly creating a bunch of empty strings. Also note that the above std::ctype<char>
facet removes all other character classification. If you want to parse other objects than just strings you might want to retain the other character classification and only change that for spaces. Here is a way this could be done:
template <char S0, char S1>
struct commactype_base {
commactype_base(): table_() {
std::transform(std::ctype<char>::classic_table(),
std::ctype<char>::classic_table() + std::ctype<char>::table_size,
this->table_,
[](std::ctype_base::mask m) -> std::ctype_base::mask {
return m & ~(std::ctype_base::space);
});
this->table_[static_cast<unsigned char>(S0)] |= std::ctype_base::space;
this->table_[static_cast<unsigned char>(S1)] |= std::ctype_base::space;
}
std::ctype<char>::mask table_[std::ctype<char>::table_size];
};
Sadly, this crashes with the version of gcc I have on my system (apparently the std::ctype<char>::classic_table()
yields a null pointer. Compiling this with a current version of clang doesn't work because clang doesn't support lambda. With the two caveats the above code should be correct, though...
Related Topics
Get Key Press in Windows Console
Const Method That Modifies *This Without Const_Cast
What Is Namespace Used For, in C++
C++ Array Size Dependent on Function Parameter Causes Compile Errors
Reading a Matrix Txt File and Storing as an Array
So_Rcvtime and So_Rcvtimeo Not Affecting Boost.Asio Operations
Dangling References and Undefined Behavior
Understanding How Lambda Closure Type Has Deleted Default Constructor
How to Get the Starting/Base Address of a Process in C++
Redirect Both Cout and Stdout to a String in C++ for Unit Testing
Why Does Destructor Disable Generation of Implicit Move Methods
How to Write Make_Unique() in VS2012
Equivalent of Console.Readline() in C++
Simulating Mouse Clicks on MAC Os X Does Not Work for Some Applications