I've been trying to compress strings and save them to text files, then read the data and decompress it. When I try to decompress the read string, however, I get a Z_BUF_ERROR (-5) and the string may or may not decompress.
In the console, I can compress/decompress all day:
std::string s = zlib_compress("HELLO asdfasdf asdf asdfasd f asd f asd f awefo#8 892y*(#Y");
std::string e = zlib_decompress(s);
The string e will return the original string with no difficulty.
However, when I do this:
zlib_decompress(readFile(filename));
I get a Z_BUF_ERROR. I think it might be due in part to hidden characters in files, but I'm not really sure.
Here's my readFile function:
std::string readFile(std::string filename)
{
std::ifstream file;
file.open(filename.c_str(), std::ios::binary);
file.seekg (0, std::ios::end);
int length = file.tellg();
file.seekg (0, std::ios::beg);
char * buffer = new char[length];
file.read(buffer, length);
file.close();
std::string data(buffer);
return data;
}
When I write the compressed data, I use:
void writeFile(std::string filename, std::string data)
{
std::ofstream file;
file.open(filename.c_str(), std::ios::binary);
file << data;
file.close();
}
If needed, I'll show the functions I use to de/compress, but if it works without the File IO, I feel that the problem is an IO problem.
First, you're dealing with binary data that might or might not have embedded null characters. std::string isn't really the correct container for that, although you can handle embedded null characters if you do it correctly. However, using a std::string to store something documents a certain expectation and you're breaking that convention.
Second, the line std::string data(buffer); isn't doing what you think it does - that is the constructor you're supposed to use to construct a string from a null-terminated C string. You're dealing with binary data here so there is a chance that you're either don't get the full buffer into the string because it encounters a null terminator in the middle of the buffer, or it runs off the end of the buffer until it finds a null (or a seg fault). If you absolutely, positively must use a std::string, use the "correct" constructor, which would be std::string data(buffer, length);.
All that said, you are using the wrong data structure - what you want is a dynamic array of char/unsigned char. That would be a std::vector, not a std::string. As an aside, you should also pass the parameters to readFileand writeFile by const reference, the code that you wrote will make copies of the strings and if the buffer you pass into writeFile() is large, that will lead to an unpleasant hit in memory consumption and performance, plus it is completely unnecessary.
As the file might contain '\0' characters, you should specify the size when you assign the content to the std::string.
std::string data(buffer, length);
For what it's worth, here's how you could alter readFile() and writeFile():
std::vector<char> readFile(const std::string& filename)
{
std::ifstream file;
file.open(filename.c_str(), std::ios::binary);
file.seekg (0, std::ios::end);
const int length = file.tellg();
file.seekg (0, std::ios::beg);
std::vector<char> data(length);
file.read(&data[0], length);
file.close();
return data;
}
void writeFile(const std::string& filename, const std::vector<char>& data)
{
std::ofstream file;
file.open(filename.c_str(), std::ios::binary);
file.write(&data[0], data.size());
file.close();
}
Then you would also change your compress() and decompress() functions to work with std::vector<char>. Also note that so far the code is lacking any error handling. For example, what happens if the file doesn't exist? After calling file.open() you can check for any error by doing if (!file) { /* error handling */ }.
Related
This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 6 years ago.
I need to read a whole file into memory and place it in a C++ std::string.
If I were to read it into a char[], the answer would be very simple:
std::ifstream t;
int length;
t.open("file.txt"); // open input file
t.seekg(0, std::ios::end); // go to the end
length = t.tellg(); // report location (this is the length)
t.seekg(0, std::ios::beg); // go back to the beginning
buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
t.read(buffer, length); // read the whole file into the buffer
t.close(); // close file handle
// ... Do stuff with buffer here ...
Now, I want to do the exact same thing, but using a std::string instead of a char[]. I want to avoid loops, i.e. I don't want to:
std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
std::getline(t, line);
// ... Append line to buffer and go on
}
t.close()
Any ideas?
There are a couple of possibilities. One I like uses a stringstream as a go-between:
std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();
Now the contents of "file.txt" are available in a string as buffer.str().
Another possibility (though I certainly don't like it as well) is much more like your original:
std::ifstream t("file.txt");
t.seekg(0, std::ios::end);
size_t size = t.tellg();
std::string buffer(size, ' ');
t.seekg(0);
t.read(&buffer[0], size);
Officially, this isn't required to work under the C++98 or 03 standard (string isn't required to store data contiguously) but in fact it works with all known implementations, and C++11 and later do require contiguous storage, so it's guaranteed to work with them.
As to why I don't like the latter as well: first, because it's longer and harder to read. Second, because it requires that you initialize the contents of the string with data you don't care about, then immediately write over that data (yes, the time to initialize is usually trivial compared to the reading, so it probably doesn't matter, but to me it still feels kind of wrong). Third, in a text file, position X in the file doesn't necessarily mean you'll have read X characters to reach that point -- it's not required to take into account things like line-end translations. On real systems that do such translations (e.g., Windows) the translated form is shorter than what's in the file (i.e., "\r\n" in the file becomes "\n" in the translated string) so all you've done is reserved a little extra space you never use. Again, doesn't really cause a major problem but feels a little wrong anyway.
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>());
I think best way is to use string stream. simple and quick !!!
#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
std::ifstream inFile;
inFile.open("inFileName"); //open the input file
std::stringstream strStream;
strStream << inFile.rdbuf(); //read the file
std::string str = strStream.str(); //str holds the content of the file
std::cout << str << "\n"; //you can do anything with the string!!!
}
You may not find this in any book or site, but I found out that it works pretty well:
#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');
Try one of these two methods:
string get_file_string(){
std::ifstream ifs("path_to_file");
return string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
string get_file_string2(){
ifstream inFile;
inFile.open("path_to_file");//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
return strStream.str();//str holds the content of the file
}
I figured out another way that works with most istreams, including std::cin!
std::string readFile()
{
stringstream str;
ifstream stream("Hello_World.txt");
if(stream.is_open())
{
while(stream.peek() != EOF)
{
str << (char) stream.get();
}
stream.close();
return str.str();
}
}
If you happen to use glibmm you can try Glib::file_get_contents.
#include <iostream>
#include <glibmm.h>
int main() {
auto filename = "my-file.txt";
try {
std::string contents = Glib::file_get_contents(filename);
std::cout << "File data:\n" << contents << std::endl;
catch (const Glib::FileError& e) {
std::cout << "Oops, an error occurred:\n" << e.what() << std::endl;
}
return 0;
}
I could do it like this:
void readfile(const std::string &filepath,std::string &buffer){
std::ifstream fin(filepath.c_str());
getline(fin, buffer, char(-1));
fin.close();
}
If this is something to be frowned upon, please let me know why
I don't think you can do this without an explicit or implicit loop, without reading into a char array (or some other container) first and ten constructing the string. If you don't need the other capabilities of a string, it could be done with vector<char> the same way you are currently using a char *.
When I use this code
std::string filename = "tmp.bin";
std::ifstream fileStream;
std::vector<unsigned char> fileBuffer;
fileStream = std::ifstream(filename.c_str(), std::ios::binary | std::ios::ate);
fileBuffer.reserve(fileStream.tellg());
fileStream.seekg(0, std::ios::beg);
fileBuffer.insert(fileBuffer.begin(), std::istream_iterator<BYTE>(fileStream), std::istream_iterator<BYTE>());
all original spaces in my binary file are skipped -> fileBuffer contains no spaces, but need all tokens for Base64 encoding.
What is wrong here?
You need to use std::istreambuf_iterator<char>, istream_iterator uses operator>> to extract data, which for char and unsigned char will skip whitespace by default.
Side note: filebufs in C++ are defined in terms of the C standard, which has the following to say in a note regarding seeking to the end of binary files:
Setting the file position indicator to end-of-file, as with fseek(file, 0, SEEK_END), has undefined behavior for a binary stream (because of possible trailing null characters) or for any stream with state-dependent encoding that does not assuredly end in the initial shift state.
It'll probably work fine regardless, but unless the reallocations are a serious issue you should just one-shot the file
std::ifstream fileStream("tmp.bin", std::ios::binary);
std::vector<char> fileBuffer{
std::istreambuf_iterator<char>(fileStream),
std::istreambuf_iterator<char>()
};
Older C++ will need to avoid a vexing parse with
std::vector<char> fileBuffer(
(std::istreambuf_iterator<char>(fileStream)),
std::istreambuf_iterator<char>()
);
If your library has char_traits for unsigned char you could also use std::basic_ifstream<unsigned char> although this isn't portable, you can always convert to unsigned char later anyway depending on what you need.
This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 6 years ago.
I need to read a whole file into memory and place it in a C++ std::string.
If I were to read it into a char[], the answer would be very simple:
std::ifstream t;
int length;
t.open("file.txt"); // open input file
t.seekg(0, std::ios::end); // go to the end
length = t.tellg(); // report location (this is the length)
t.seekg(0, std::ios::beg); // go back to the beginning
buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
t.read(buffer, length); // read the whole file into the buffer
t.close(); // close file handle
// ... Do stuff with buffer here ...
Now, I want to do the exact same thing, but using a std::string instead of a char[]. I want to avoid loops, i.e. I don't want to:
std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
std::getline(t, line);
// ... Append line to buffer and go on
}
t.close()
Any ideas?
There are a couple of possibilities. One I like uses a stringstream as a go-between:
std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();
Now the contents of "file.txt" are available in a string as buffer.str().
Another possibility (though I certainly don't like it as well) is much more like your original:
std::ifstream t("file.txt");
t.seekg(0, std::ios::end);
size_t size = t.tellg();
std::string buffer(size, ' ');
t.seekg(0);
t.read(&buffer[0], size);
Officially, this isn't required to work under the C++98 or 03 standard (string isn't required to store data contiguously) but in fact it works with all known implementations, and C++11 and later do require contiguous storage, so it's guaranteed to work with them.
As to why I don't like the latter as well: first, because it's longer and harder to read. Second, because it requires that you initialize the contents of the string with data you don't care about, then immediately write over that data (yes, the time to initialize is usually trivial compared to the reading, so it probably doesn't matter, but to me it still feels kind of wrong). Third, in a text file, position X in the file doesn't necessarily mean you'll have read X characters to reach that point -- it's not required to take into account things like line-end translations. On real systems that do such translations (e.g., Windows) the translated form is shorter than what's in the file (i.e., "\r\n" in the file becomes "\n" in the translated string) so all you've done is reserved a little extra space you never use. Again, doesn't really cause a major problem but feels a little wrong anyway.
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>());
I think best way is to use string stream. simple and quick !!!
#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
std::ifstream inFile;
inFile.open("inFileName"); //open the input file
std::stringstream strStream;
strStream << inFile.rdbuf(); //read the file
std::string str = strStream.str(); //str holds the content of the file
std::cout << str << "\n"; //you can do anything with the string!!!
}
You may not find this in any book or site, but I found out that it works pretty well:
#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');
Try one of these two methods:
string get_file_string(){
std::ifstream ifs("path_to_file");
return string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
string get_file_string2(){
ifstream inFile;
inFile.open("path_to_file");//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
return strStream.str();//str holds the content of the file
}
I figured out another way that works with most istreams, including std::cin!
std::string readFile()
{
stringstream str;
ifstream stream("Hello_World.txt");
if(stream.is_open())
{
while(stream.peek() != EOF)
{
str << (char) stream.get();
}
stream.close();
return str.str();
}
}
If you happen to use glibmm you can try Glib::file_get_contents.
#include <iostream>
#include <glibmm.h>
int main() {
auto filename = "my-file.txt";
try {
std::string contents = Glib::file_get_contents(filename);
std::cout << "File data:\n" << contents << std::endl;
catch (const Glib::FileError& e) {
std::cout << "Oops, an error occurred:\n" << e.what() << std::endl;
}
return 0;
}
I could do it like this:
void readfile(const std::string &filepath,std::string &buffer){
std::ifstream fin(filepath.c_str());
getline(fin, buffer, char(-1));
fin.close();
}
If this is something to be frowned upon, please let me know why
I don't think you can do this without an explicit or implicit loop, without reading into a char array (or some other container) first and ten constructing the string. If you don't need the other capabilities of a string, it could be done with vector<char> the same way you are currently using a char *.
This question already has answers here:
How do I read an entire file into a std::string in C++?
(23 answers)
Closed 6 years ago.
I need to read a whole file into memory and place it in a C++ std::string.
If I were to read it into a char[], the answer would be very simple:
std::ifstream t;
int length;
t.open("file.txt"); // open input file
t.seekg(0, std::ios::end); // go to the end
length = t.tellg(); // report location (this is the length)
t.seekg(0, std::ios::beg); // go back to the beginning
buffer = new char[length]; // allocate memory for a buffer of appropriate dimension
t.read(buffer, length); // read the whole file into the buffer
t.close(); // close file handle
// ... Do stuff with buffer here ...
Now, I want to do the exact same thing, but using a std::string instead of a char[]. I want to avoid loops, i.e. I don't want to:
std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
std::getline(t, line);
// ... Append line to buffer and go on
}
t.close()
Any ideas?
There are a couple of possibilities. One I like uses a stringstream as a go-between:
std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();
Now the contents of "file.txt" are available in a string as buffer.str().
Another possibility (though I certainly don't like it as well) is much more like your original:
std::ifstream t("file.txt");
t.seekg(0, std::ios::end);
size_t size = t.tellg();
std::string buffer(size, ' ');
t.seekg(0);
t.read(&buffer[0], size);
Officially, this isn't required to work under the C++98 or 03 standard (string isn't required to store data contiguously) but in fact it works with all known implementations, and C++11 and later do require contiguous storage, so it's guaranteed to work with them.
As to why I don't like the latter as well: first, because it's longer and harder to read. Second, because it requires that you initialize the contents of the string with data you don't care about, then immediately write over that data (yes, the time to initialize is usually trivial compared to the reading, so it probably doesn't matter, but to me it still feels kind of wrong). Third, in a text file, position X in the file doesn't necessarily mean you'll have read X characters to reach that point -- it's not required to take into account things like line-end translations. On real systems that do such translations (e.g., Windows) the translated form is shorter than what's in the file (i.e., "\r\n" in the file becomes "\n" in the translated string) so all you've done is reserved a little extra space you never use. Again, doesn't really cause a major problem but feels a little wrong anyway.
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>());
I think best way is to use string stream. simple and quick !!!
#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
std::ifstream inFile;
inFile.open("inFileName"); //open the input file
std::stringstream strStream;
strStream << inFile.rdbuf(); //read the file
std::string str = strStream.str(); //str holds the content of the file
std::cout << str << "\n"; //you can do anything with the string!!!
}
You may not find this in any book or site, but I found out that it works pretty well:
#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');
Try one of these two methods:
string get_file_string(){
std::ifstream ifs("path_to_file");
return string((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
}
string get_file_string2(){
ifstream inFile;
inFile.open("path_to_file");//open the input file
stringstream strStream;
strStream << inFile.rdbuf();//read the file
return strStream.str();//str holds the content of the file
}
I figured out another way that works with most istreams, including std::cin!
std::string readFile()
{
stringstream str;
ifstream stream("Hello_World.txt");
if(stream.is_open())
{
while(stream.peek() != EOF)
{
str << (char) stream.get();
}
stream.close();
return str.str();
}
}
If you happen to use glibmm you can try Glib::file_get_contents.
#include <iostream>
#include <glibmm.h>
int main() {
auto filename = "my-file.txt";
try {
std::string contents = Glib::file_get_contents(filename);
std::cout << "File data:\n" << contents << std::endl;
catch (const Glib::FileError& e) {
std::cout << "Oops, an error occurred:\n" << e.what() << std::endl;
}
return 0;
}
I could do it like this:
void readfile(const std::string &filepath,std::string &buffer){
std::ifstream fin(filepath.c_str());
getline(fin, buffer, char(-1));
fin.close();
}
If this is something to be frowned upon, please let me know why
I don't think you can do this without an explicit or implicit loop, without reading into a char array (or some other container) first and ten constructing the string. If you don't need the other capabilities of a string, it could be done with vector<char> the same way you are currently using a char *.
I'd like to read whole content of a text file to a std::string object with c++.
With Python, I can write:
text = open("text.txt", "rt").read()
It is very simple and elegant. I hate ugly stuff, so I'd like to know - what is the most elegant way to read a text file with C++?
Thanks.
There are many ways, you pick which is the most elegant for you.
Reading into char*:
ifstream file ("file.txt", ios::in|ios::binary|ios::ate);
if (file.is_open())
{
file.seekg(0, ios::end);
size = file.tellg();
char *contents = new char [size];
file.seekg (0, ios::beg);
file.read (contents, size);
file.close();
//... do something with it
delete [] contents;
}
Into std::string:
std::ifstream in("file.txt");
std::string contents((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
Into vector<char>:
std::ifstream in("file.txt");
std::vector<char> contents((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
Into string, using stringstream:
std::ifstream in("file.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());
file.txt is just an example, everything works fine for binary files as well, just make sure you use ios::binary in ifstream constructor.
There's another thread on this subject.
My solutions from this thread (both one-liners):
The nice (see Milan's second solution):
string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());
and the fast:
string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());
You seem to speak of elegance as a definite property of "little code". This is ofcourse subjective in some extent. Some would say that omitting all error handling isn't very elegant. Some would say that clear and compact code you understand right away is elegant.
Write your own one-liner function/method which reads the file contents, but make it rigorous and safe underneath the surface and you will have covered both aspects of elegance.
All the best
/Robert
But beware that a c++-string (or more concrete: An STL-string) is as little as a C-String capable of holding a string of arbitraty length - of course not!
Take a look at the member max_size() which gives you the maximum number of characters a string might contain. This is an implementation definied number and may not be portable among different platforms. Visual Studio gives a value of about 4gigs for strings, others might give you only 64k and on 64Bit-platforms it might give you something really huge! It depends and of course normally you will run into a bad_alloc-exception due to memory exhaustion a long time before reaching the 4gig limit...
BTW: max_size() is a member of other STL-containers as well! It will give you the maximum number of elements of a certain type (for which you instanciated the container) which this container will (theoretically) be able to hold.
So, if you're reading from a file of unknow origin you should:
- Check its size and make sure it's smaller than max_size()
- Catch and process bad_alloc-exceptions
And another point:
Why are you keen on reading the file into a string? I would expect to further process it by incrementally parsing it or something, right? So instead of reading it into a string you might as well read it into a stringstream (which basically is just some syntactic sugar for a string) and do the processing. But then you could do the processing directly from the file as well. Because if properly programmed the stringstream could seamlessly be replaced by a filestream, i. e. by the file itself. Or by any other input stream as well, they all share the same members and operators and can thus be seamlessly interchanged!
And for the processing itself: There's also a lot you can have automated by the compiler! E. g. let's say you want to tokenize the string. When defining a proper template the following actions:
- Reading from a file (or a string or any other input stream)
- Tokenizing the content
- pushing all found tokens into an STL-container
- sort the tokens alphabetically
- eleminating any double values
can all(!!) be achived in one single(!) line of C++-code (let aside the template itself and the error handling)! It's just a single call of the function std::copy()! Just google for "token iterator" and you'll get an idea of what I mean. So this appears to me to be even more "elegant" than just reading from a file...
I like Milan's char* way, but with std::string.
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
string& getfile(const string& filename, string& buffer) {
ifstream in(filename.c_str(), ios_base::binary | ios_base::ate);
in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
buffer.resize(in.tellg());
in.seekg(0, ios_base::beg);
in.read(&buffer[0], buffer.size());
return buffer;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cerr << "Usage: this_executable file_to_read\n";
return EXIT_FAILURE;
}
string buffer;
cout << getfile(argv[1], buffer).size() << "\n";
}
(with or without the ios_base::binary, depending on whether you want newlines tranlated or not. You could also change getfile to just return a string so that you don't have to pass a buffer string in. Then, test to see if the compiler optimizes the copy out when returning.)
However, this might look a little better (and be a lot slower):
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
using namespace std;
string getfile(const string& filename) {
ifstream in(filename.c_str(), ios_base::binary);
in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>());
}
int main(int argc, char* argv[]) {
if (argc != 2) {
cerr << "Usage: this_executable file_to_read\n";
return EXIT_FAILURE;
}
cout << getfile(argv[1]).size() << "\n";
}