Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how can I read exactly 128 bytes from an fstream into a string object? [duplicate]

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;
}
like image 411
Southern Hospitality Avatar asked Aug 22 '10 04:08

Southern Hospitality


2 Answers

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) );
like image 69
ngoozeff Avatar answered Sep 22 '22 17:09

ngoozeff


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.

like image 30
Brent Bradburn Avatar answered Sep 26 '22 17:09

Brent Bradburn