2012-01-26 17 views
9

双方向イテレータ/アダプタを持つ入力ファイルストリームが必要です。ファイル/ ifstreamの双方向イテレータ

残念ながら、std::ifstream(以下同様)は、逆方向に進むことのできない順方向イテレータの一種であるstd::istream_iteratorでのみ使用できます。 (または、私がここに間違っています?)

私は単にメモリにファイル全体をロードし、アレイの上にはるかに強力なランダム・アクセス反復子を使用することができます。しかし、私はそれを避けたいと思って、私が本当に必要とするものだけを読む。私は本当にファイルのほんの一部しか必要としないことがあります。

私は何とかそれを手動でCにstdio.h機能を使用して行うことができますが、それは痛みを伴うだろう。私は基本的に、その仕様を念頭に置いた双方向イテレータを手作業で実装する必要があります。

私はブーストiostreamライブラリに探して検討していますが、マニュアルはやや圧倒的で、私は誰かがこの特定の目標を達成するために私の手を与えることができる期待していましたか?あるいは、私が必要とするものをまさに実行するための既存のライブラリがもう1つありますか?

私はイテレータがインクリメントだけでなく、減算することができますことを期待し、私のファイルを解析するために、ブーストxpressiveライブラリのためのイテレータを必要とします。これは必須条件ではありませんが、私が読んでいるファイルがバッファリングされていれば問題ありません。

アイデア? ありがとうございました!

+1

双方向イテレータが必要ですか?前方イテレータは十分であろう場合は、[Boost.Spirit](http://www.boost.org/libs/spirit/)あなたがカバーしている:[ライブラリのサポート - >マルチパス・イテレータを](HTTP://www.boost .org/libs/spirit/doc/html/spirit/support/multi_pass.html)。 – ildjarn

+0

ファイルの一部をバッファしたり、操作したり、一時ファイルに書き込んだり、ファイルの次の部分を取得したりすることはできませんか? –

+1

私はそれを取るだけでメモリマップファイルできないのですか?もちろんポータブルではありませんが、ランダムアクセスが可能です。*実際に必要なファイルの部分だけが読み込まれます(まあ、ページサイズに切り上げられた部分の近傍)。 –

答えて

5

私が間違った方向にファイルをトラバースすると、私は自分の要求に疑問を呈し始めます。これは物事を行うための工夫された方法であり、おそらく何かが劇的にどこかに乱されているようです。

私は、これは確かに私たちは間違いなくここにファイルを話し、のではなく、例えばされていることを理解するであろう要件であることを確認したら、名前付きパイプまたはソケット。つまり、ファイルの少なくとも一部をメモリマップでマップすることができます。私はこれを使用してメモリを歩くイテレータを作成します。明らかにイテレータが必要なので、ストリームを含める必要はありません。ストリームが必要だった場合は、ファイルとバックバッファをカスタムストリームバッファ内のメモリから順番にマップします。

実際に最初から読んで、必要に応じて後ろに移動できるようにする必要がある場合は、これよりも簡単です:既に読み込まれたデータのバッファを保持し、終了イテレータを使用して後方へ移動する場合は、このファイルに対処する必要があります。ここでは、確かに前方のファイルを読み込むと後方できるコードがあるが、完全にテストされていません。

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

ちょうどあなたが引数として読み、その後、実際にbegin()end()メソッドを使用したいストリームとbidirectional_streamを作成しますそれにアクセスする。

+0

"*私が間違った方向にファイルをたどると、私は自分の要求に疑問を呈しています。* "これは[Boost.Xpressive](http://www.boost.org/libs/xpressive/)の要件であり、OPの直接要求ではありません。 – ildjarn

+0

その後、元の著者はBoost.Xpressiveを間違ったものに使っています!間違った方法でファイルを読むのは、あまり効率的ではありません。いくつかのライブラリで使用するかどうかは、ファイルの後ろを読む必要があります。 –

+3

申し訳ありませんが、ファイルの内容の正規表現を実行することは、風変わりなことのようには聞こえません。正規表現への入力としてファイルストリームを使用するのは間違っているかもしれませんが、それは間違っている可能性があります。全体的な目標は確かにない疑わしい。 – ildjarn

3

あなたはすでにあなたが開始イテレータとfile.data(としてfile.dataを()を使用することができますboost::iostreams::mapped_file_sourcehttp://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/mapped_file.html#mapped_file_source

を見て、ブーストを使用しているので)+ file.size()終了イテレータとしては、 。

+0

私はdefinetely mapped_file_sourceを調べます。私が必要なものを達成するためにそれを使用する方法の例を私に提供できるのであれば、本当に役に立ちますか? – CygnusX1

+0

@ CygnusX1 'boost :: iostreams :: mapped_file_sourceファイル(" whatever.bin ");と書いてください。あなたはあなたのファイルを持っています。 'reverse_copy(file.data()、file.data()+ file.size()、std :: ostreambuf_iterator (std :: cout));または実際にランダムにアクセスします。 – Cubbi

+0

あなたがポインタのペアからreverse_copyできるようになる前に、make_iterator_rangeが必要なのは、最良の例ではありませんでした。 – Cubbi