c++vectorstlstreamifstream

How can I read an entire stream of bytes into an std::vector?


I read an answer here showing how to read an entire stream into a std::string with the following one (two) liner:

std::istreambuf_iterator<char> eos;    
std::string s(std::istreambuf_iterator<char>(stream), eos);

For doing something similar to read a binary stream into a std::vector, why can't I simply replace char with uint8_t and std::string with std::vector?

auto stream = std::ifstream(path, std::ios::in | std::ios::binary);    
auto eos = std::istreambuf_iterator<uint8_t>();
auto buffer = std::vector<uint8_t>(std::istreambuf_iterator<uint8_t>(stream), eos);

The above produces a compiler error (VC2013):

1>d:\non-svn\c++\library\i\file\filereader.cpp(62): error C2440: '' : cannot convert from 'std::basic_ifstream>' to 'std::istreambuf_iterator>' 1>
with 1> [ 1> _Elem=uint8_t 1> ] 1>
No constructor could take the source type, or constructor overload resolution was ambiguous


Solution

  • There's just a type mismatch. ifstream is just a typedef:

    typedef basic_ifstream<char> ifstream;
    

    So if you want to use a different underlying type, you just have to tell it:

    std::basic_ifstream<uint8_t> stream(path, std::ios::in | std::ios::binary);    
    auto eos = std::istreambuf_iterator<uint8_t>();
    auto buffer = std::vector<uint8_t>(std::istreambuf_iterator<uint8_t>(stream), eos);
    

    That works for me.

    Or, since Dietmar says this might be a little sketchy, you could do something like:

    auto stream = std::ifstream(...);
    std::vector<uint8_t> data;
    
    std::for_each(std::istreambuf_iterator<char>(stream),
                  std::istreambuf_iterator<char>(),
                  [&data](const char c){
                      data.push_back(c);
                  });