2012-01-26 20 views
9

Çift yönlü yineleyici/bağdaştırıcıya sahip bir giriş dosyası akışına ihtiyacım var.dosya üzerinden çift yönlü yineleyici dosya/ifstream

Maalesef std::ifstream (ve benzeri) yalnızca geriye doğru gidemeyen bir tür ileri yineleyici olan std::istream_iterator ile kullanılabilir. (Ya da burada yanılıyorum?)

Tüm dosyayı belleğe yükleyebilir ve ardından dizi üzerinde çok daha güçlü bir rasgele erişimli yineleyici kullanabilirim; Ancak bundan kaçınmak ve gerçekten ihtiyacım olan kadar okumak istiyorum. Bir dosyanın sadece küçük bir kısmına gerçekten ihtiyacım olabilir.

Bunu bir şekilde C stdio.h işlevlerini kullanarak yapabilirim, ancak bu acı verici olur. Temel olarak eldeki tüm özellikleriyle birlikte, iki yönlü bir yineleyiciyi uygulamaya ihtiyacım var.

iostream kütüphanesini desteklemeyi düşünüyorum, ancak el kitabı biraz bunaltıcı, bu özel hedefe ulaşmak için bana bir yardım verebileceğini umuyordum? Ya da belki de ihtiyacım olan şeyi yapmak için zaten var olan başka bir kütüphane var mı?

Dosyalarıma ayrıştırmak için yükseltici xpressive kitaplığı için yineleyiciye ihtiyacım var, bu da yineleyicinin artırılıp azaltılabileceğini umar. Okumak dosya tamponlu olsa iyi olurdu, ancak bu bir gereklilik değil.

Herhangi bir fikrin var mı? Teşekkür ederiz!

+1

İki yönlü bir yineleyiciye ihtiyacınız olduğundan emin misiniz? Bir ileri yineleyici yeterliyse, [Boost.Spirit] (http://www.boost.org/libs/spirit/): [Destekleyen Kütüphaneler -> Çok geçişli yineleyici] (http: //www.boost) .org/kütüphaneleri/alkol/doc/html/alkol/destek/multi_pass.html). – ildjarn

+0

Dosyanın bir parçasını tamponlayamaz, işlemlerinizi bunun üzerine yapabilir, geçici bir dosyaya yazabilir, sonra dosyanın bir sonraki bölümünü alabilirsin, vb. –

+1

Anladığım kadarıyla sadece dosyayı haritaya aktaramazsın? Tabii ki daha az taşınabilir, ancak size rastgele erişim sağlar * ve * sadece gerçekten ihtiyacınız olan dosyanın bölümlerini okur (iyi, bu bölümlerin mahalleleri, bazı sayfa boyutlarına yuvarlanır). –

cevap

5

Bir dosyayı yanlış yöne kaydırırsam, gereksinimlerimi sorgulamaya başlıyorum. Bu, bir şeyler yapmanın zorlu bir yolu gibi görünüyor ve büyük olasılıkla bir yerlerde önemli ölçüde bir yere bulaşmış durumda.

Bunun gerçekten bir gereklilik olduğunu teyit ettikten sonra, kesinlikle dosyalardan değil, adlandırılmış bir boru veya soket. Yani, en azından dosyanın bazı bölümlerinde bellek haritası olabilir. Bunu, belleği gezen bir yineleyici oluşturmak için kullanırdım. Açıkça bir yineleyiciye ihtiyaç duyulduğundan, akışları içermeye gerek yoktur. Akımlar da gerekliyse, yine de dosyayı eşlemek için bellek eşleştirip, özel bir akış arabelleğinde arkadaki arabellekleri tersine çeviririm.

Aslında başlangıçtan okuduğunda ve gerektiğinde geriye doğru hareket edebilmeye ihtiyaç duyduğunda, bundan daha basit olabilir: zaten okunan verilerin bir arabelleğinin tutulması ve uçtan çıkarken harcanması artı muhtemelen tüm okunması son yineleyici geriye doğru hareket etmek için kullanılırsa, bu sorunu ele almalıdır. Burada kesinlikle ileriye bir dosyayı okuyabilir kodu ve geriye doğru ama iyice test değildir:

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

Sadece bir argüman olarak okumak ve ardından begin() ve end() yöntemlerini kullanmak istediğiniz akımına sahip bir bidirectional_stream oluşturmak aslında Ona eriş. Zaten boost özelliğini kullandığınız için

+0

"Eğer bir dosyayı yanlış yöne çevirirsem, Gereksinimlerimi sorgulamaya başlayacağım. * "Bunlar [Boost.Xpressive] gereklilikleridir (http://www.boost.org/libs/xpressive/), OP – ildjarn

+0

'un direkt gereksinimleri değil, daha sonra orijinal yazar Yanlış şeyler üzerinde Boost.Xpressive kullanarak! Yanlış bir şekilde bir dosya okuma, çok verimli olmayacaktır.Onun bazı kütüphane için kullanılacak olup olmadığı tamamen dışındadır: dosyanın arkasını okumak için gereklilik yanlış bir düzen var gibi görünüyor ve ben gerekli olduğunu sorgulamak istiyorum. –

+3

Üzgünüz, ama dosya içeriği üzerinde bir regex çalıştırmak yapmak için bir outlandish gibi gelmiyor.Regex giriş olarak bir dosya akışı kullanarak yanlış yönlendirilmiş olabilir, ancak genel hedef kesinlikle hayır sorgulanabilir. – ildjarn

3

,

Sen olarak file.data() kullanabilir boost::iostreams::mapped_file_sourcehttp://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/mapped_file.html#mapped_file_source

bakmak uç yineleyici olarak yineleyici ve file.data() + file.size() başlayacak .

+0

Mapped_file_source'a kesinlikle bakacağım. İhtiyacım olanı elde etmek için nasıl kullanacağım konusunda bana bir örnek verebilirseniz gerçekten yararlı olur mu? – CygnusX1

+0

@ CygnusX1 Sadece yazınız: boost :: iostreams :: mapped_file_source file ("whatever.bin"); 've dosyanızı tersine çevirebilirsiniz, örn. reverse_copy (file.data(), file.data() + dosya.size(), std :: ostreambuf_iterator (std :: cout)) veya aslında rasgele erişim. – Cubbi

+0

Er, bir çift işaretçiden tersine kopyalayabilmeniz için make_iterator_range var, en iyi örnek değildi. – Cubbi

İlgili konular