Чтение частичного потока файла в строку с использованием итераторов - PullRequest
6 голосов
/ 03 ноября 2010

Это то, что я пробовал до сих пор, но безуспешно:

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 ); 
}

Я знаю, как читать весь файл.

std::string Read( std::ifstream& _file )
{
    std::istreambuf_iterator<char> first( _file );
    std::istreambuf_iterator<char> last();
    return std::string( first, last ); 
}

Но это не то, что я хочусделать.Я получаю пустую строку.Если я смотрю первый и последний в отладчике, они указывают на одну и ту же вещь даже после std :: advance.

Ответы [ 3 ]

5 голосов
/ 03 ноября 2010
std::istreambuf_iterator<char> first( _file );
std::istreambuf_iterator<char> last( _file );
std::advance( last, _size );

istreambuf_iterators - это итераторы ввода.Когда вы продвигаетесь последним, другой итератор также изменяется. Вы рассматриваете их как прямые итераторы, у которых есть свойство, что вы можете скопировать итератор, продвинуть его, а затем получить идентичную последовательность, продвигая копию.

Для общего случая:

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;
}

Однако в этом случае вам лучше изменить размер строки, используя istream :: read непосредственно в & result [0], и, наконец, проверитьчто вы прочитали нужное количество символов.

5 голосов
/ 03 ноября 2010

Есть ли какая-то особая причина, по которой вы хотите использовать итераторы?Вы можете просто прочитать байты за один раз:

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

Если вы действительно хотите читать с использованием итераторов, вы можете сделать это:

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;
}
1 голос
/ 03 ноября 2010

Не существует стандартного алгоритма, который мог бы вам здесь помочь, но вы можете использовать этот:

template< class InputIterator, class OutputIterator>
OutputIterator copy_n(InputIterator from,
                      size_t n,
                      OutputIterator to)
{
    while (n)
    {
        *to = *from;
        ++from;
        ++to;
        --n;
    }
    return to;
}

Этот вариант можно использовать с ReadPartial, например:

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; 
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...