Reputation: 145
This is what I have tried so far but with no success:
std::string ReadPartial( std::ifstream& _file, int _size )
{
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last( _file );
std::advance( last, _size );
return std::string( first, last );
}
I know how to read the whole file.
std::string Read( std::ifstream& _file )
{
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last();
return std::string( first, last );
}
But this is not what i want to do. I'm getting an empty string. If I look at first and last in a debugger they point to the same thing even after the std::advance.
Upvotes: 8
Views: 3106
Reputation: 185902
Is there some particular reason you want to use iterators? You could just read the bytes in one go:
std::string s(_size, '\0');
_file.read(&s[0], _size);
If you really want to read using iterators, you could do this:
std::string ReadPartial( std::ifstream& _file, int _size )
{
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last;
std::string s;
s.reserve(_size);
while (_size-- && first != last) s += *first++;
return s;
}
Upvotes: 6
Reputation:
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last( _file );
std::advance( last, _size );
istreambuf_iterators are Input Iterators. Once you advance last, the other iterator is modified too. You are treating them as Forward Iterators, which have the property that you can copy an iterator, advance it, then get an identical sequence by advancing the copy.
For the general case:
template<class InIter, class Size, class OutIter>
void copy_n(InIter begin, InIter end, Size n, OutIter dest) {
for (; begin != end && n > 0; ++begin, --n) {
*dest++ = *begin;
}
}
//...
std::string ReadPartial(std::istream& file, int size) {
std::string result;
copy_n(istreambuf_iterator<char>(file), istreambuf_iterator<char>(),
size, back_inserter(result));
return result;
}
However, in this case, you would be better off resizing the string, using istream::read directly into &result[0], and finally checking that you read the desired number of characters.
Upvotes: 6
Reputation: 15768
There is no standard algorithm that can help you here, but you can use this one:
template< class InputIterator, class OutputIterator>
OutputIterator copy_n(InputIterator from,
size_t n,
OutputIterator to)
{
while (n)
{
*to = *from;
++from;
++to;
--n;
}
return to;
}
This can be used with ReadPartial
like this:
std::string ReadPartial( std::ifstream& _file, int _size )
{
std::istreambuf_iterator<char> first( _file );
std::string result;
copy_n(first, _size, std::back_inserter(result));
return result;
}
Upvotes: 1