Reading a partial file stream into a string using iterators

This is what I have tried so far, but without 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 that is not what I want to do. I get an empty string. If I look first and last in the debugger, they point to the same thing even after std :: advance.

+6
c ++ iterator string
source share
3 answers

Is there any specific reason why you want to use iterators? You could just read the bytes at a time:

 std::string s(_size, '\0'); _file.read(&s[0], _size); 

If you really want to read using iterators, you can 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; } 
+5
source share
 std::istreambuf_iterator<char> first( _file ); std::istreambuf_iterator<char> last( _file ); std::advance( last, _size ); 

istreambuf_iterators are input iterators. As soon as you advance last, the iterator changes. You see them as Forward Iterators, which have a property that you can copy an iterator, promote it, and then get an identical sequence by promoting the copy.

In general:

 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 are better off resizing the string using istream :: read directly in & result [0] and finally checking that you are reading the correct number of characters.

+5
source share

There is no standard algorithm that can help you here, but you can use it:

 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 as follows:

 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; } 
+1
source share

All Articles