Если бы я перебирал файл в неправильном направлении, я бы начал сомневаться в своих требованиях. Похоже, что это искусственный способ сделать что-то, и, скорее всего, что-то где-то резко испортилось.
Как только я подтвердил, что это действительно требование, я понял, что мы определенно говорим здесь, а не, например. именованная труба или сокет. То есть была бы возможна карта памяти хотя бы части файла. Я хотел бы использовать это для создания итератора, который обходит память. Поскольку, очевидно, нужен итератор, нет необходимости привлекать потоки. Если бы понадобились и потоки, я бы все равно использовал карту памяти и обратные буферы со спины в пользовательском буфере потоков.
Когда вы на самом деле читаете с самого начала и просто нуждаетесь в возможности перемещаться назад, когда это необходимо, это может быть проще, чем это: хранить буфер уже прочитанных данных и расширять его при перемещении с конца, а также, возможно, читать весь файл если конечный итератор используется для перемещения назад, следует обратиться к этому. Вот код, который, безусловно, может читать файл вперед и назад, но не проходит тщательного тестирования:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <limits>
#include <vector>
class bidirectional_stream
{
public:
class iterator;
typedef iterator const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
bidirectional_stream(std::istream& in):
in_(in)
{
}
iterator begin();
iterator end();
reverse_iterator rbegin();
reverse_iterator rend();
bool expand()
{
char buffer[1024];
this->in_.read(buffer, sizeof(buffer));
this->buffer_.insert(this->buffer_.end(), buffer, buffer + this->in_.gcount());
return 0 < this->in_.gcount();
}
long read_all()
{
this->buffer_.insert(this->buffer_.end(),
std::istreambuf_iterator<char>(this->in_),
std::istreambuf_iterator<char>());
return this->buffer_.size();
}
char get(long index) { return this->buffer_[index]; }
long current_size() const { return this->buffer_.size(); }
private:
std::istream& in_;
std::vector<char> buffer_;
};
class bidirectional_stream::iterator
{
public:
typedef char value_type;
typedef char const* pointer;
typedef char const& reference;
typedef long difference_type;
typedef std::bidirectional_iterator_tag iterator_category;
iterator(bidirectional_stream* context, size_t pos):
context_(context),
pos_(pos)
{
}
bool operator== (iterator const& other) const
{
return this->pos_ == other.pos_
|| (this->pos_ == this->context_->current_size()
&& !this->context_->expand()
&& other.pos_ == std::numeric_limits<long>::max());
}
bool operator!= (iterator const& other) const { return !(*this == other); }
char operator*() const { return this->context_->get(this->pos_); }
iterator& operator++() { ++this->pos_; return *this; }
iterator operator++(int) { iterator rc(*this); this->operator++(); return rc; }
iterator& operator--()
{
if (this->pos_ == std::numeric_limits<long>::max())
{
this->pos_ = this->context_->read_all();
}
--this->pos_;
return *this;
}
iterator operator--(int) { iterator rc(*this); this->operator--(); return rc; }
private:
bidirectional_stream* context_;
long pos_;
};
bidirectional_stream::iterator bidirectional_stream::begin()
{
return iterator(this, 0);
}
bidirectional_stream::iterator bidirectional_stream::end()
{
return iterator(this, std::numeric_limits<long>::max());
}
bidirectional_stream::reverse_iterator bidirectional_stream::rbegin()
{
return reverse_iterator(this->end());
}
bidirectional_stream::reverse_iterator bidirectional_stream::rend()
{
return reverse_iterator(this->begin());
}
Просто создайте bidirectional_stream
с потоком, который вы хотите прочитать в качестве аргумента, а затем используйте методы begin()
и end()
для фактического доступа к нему.