How do I read exactly 128 bytes from an fstream into a string object?
I wrote some code to read the first 128 bytes of a file and print it and then the last 128 bytes of the file and print that. The last part works, since you can easily iterate to EOF, but how do I get exactly 128 bytes from the front? The code below doesn't work since you can't add 128 to an ifstream iterator, it's not indexable, only incrementable (it seems).
Sure I could make an iterator and *++ it 128 times, but there must be a single line straightforward way to do it, right?
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char **argv)
{
std::ifstream ifs ("input.txt",std::ifstream::in | std::ifstream::binary);
if (ifs.good())
{
// read first 128 bytes into a string
ifs.seekg(0,std::ifstream::beg);
std::string first128((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>(ifs))+128);
std::cout << first128 << std::endl;
// read last 128 bytes into a string
ifs.seekg(-128,std::ifstream::end);
std::string last128((std::istreambuf_iterator<char>(ifs)),
std::istreambuf_iterator<char>());
std::cout << last128 << std::endl;
return 0;
}
return 1;
}
char buffer[129];
ifs.read (buffer,128);
buffer[128] = '\0';
first128 = buffer;
How about this then:
template <typename Itr, typename Out>
void copy_n(Itr it, size_t count, Out out)
{
for(size_t i=0;i<count;++i)
out = *it++;
}
...
std::string first128;
std::istreambuf_iterator<char> it(ifs);
copy_n( it, 128,
std::back_inserter<std::string>(first128) );
My answer uses an intermediate buffer, but perhaps you will be happy that it uses iterators to initialize the string from the buffer.
std::vector<char> buffer(128); // create a buffer
ifs.read( &buffer[0], buffer.size() ); // read to buffer
std::string first128( buffer.begin(), buffer.end() ); // copy from vector
To me it seems like they got a little too cute with the implementation of iostreams. Trying to use iterators for stream I/O is overly complicated.
By the way, I suspect the implementation that you were attempting will, under the covers, do a variety of intermediate buffering (perhaps some in the kernel, some in the library) as well as re-allocating and copying the string several times as it grows.
One other idea: Do you really need the result in a standard string? You might just work from the vector -- avoiding the final step of copying to a string. Or, if you are feeling adventurous, you could create your own string class that does allow you to expose the internal buffer in the same way that vector does.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With