2012-01-26 3 views
9

양방향 반복기/어댑터가있는 입력 파일 스트림이 필요합니다.파일/ifstream의 양방향 반복기

불행히도 std::ifstream (및 이와 유사한)은 역방향으로 진행할 수없는 순방향 반복기의 일종 인 std::istream_iterator에서만 사용할 수 있습니다. (아니면 내가 여기 오인입니까?)

전체 파일을 메모리에로드 한 다음 배열에 대해 훨씬 더 강력한 임의 액세스 반복기를 사용할 수 있습니다. 그러나 나는 그것을 피하고, 내가 정말로 필요로하는만큼 많이 읽고 싶다. 정말 파일의 일부만 필요로 할 수도 있습니다.

나는 C stdio.h 함수를 사용하여 수동으로 할 수 있지만 고통 스러울 것입니다. 나는 기본적으로 모든 명세를 염두에두고 직접 양방향 반복기를 구현해야한다.

iostream 라이브러리를 향상시키는 방법을 고려하고 있지만 설명서가 다소 압도적인데 누군가가이 특별한 목표를 달성하기 위해 나에게 도움이되기를 바랍니다. 아니면 내가 필요로하는 것을 수행하기 위해 이미 기존의 다른 라이브러리가 있습니까?

내 파일을 구문 분석하기위한 boost xpressive 라이브러리의 반복기가 필요합니다. 반복기가 증가하고 감소 할 것으로 예상됩니다. 이것이 요구 사항은 아니지만, 내가 읽고있는 파일이 버퍼링되면 괜찮을 것입니다.

아이디어가 있으십니까? 감사합니다.

+1

양방향 반복기가 필요합니까? forward iterator로 충분하다면, [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

잘못된 방향으로 파일을 트래버스하면 필자는 요구 사항에 대해 질문을 시작할 것입니다. 이것은 일을하는 고안된 방법 인 것 같고 무언가가 어딘가에서 극적으로 엉망이 될 가능성이 큽니다.

이것이 실제로 요구 사항이라는 것을 확인한 후에는 예를 들어 Google이 여기보다는 확실히 파일을 말하고 있다는 것을 깨달았습니다. 명명 된 파이프 또는 소켓 즉, 메모리 맵이 파일의 적어도 일부분 일 수 있습니다. 나는 이것을 사용하여 메모리를 걷는 반복자를 만든다. 분명히 반복자가 필요하기 때문에 스트림을 포함 할 필요가 없습니다. 스트림이 필요한 경우에도 사용자 지정 스트림 버퍼의 파일과 리버스 버퍼를 메모리 맵핑 할 것입니다.

실제로 처음부터 읽고 필요할 때 뒤로 이동할 수있을 때, 이미 읽은 데이터의 버퍼를 유지하고 끝에서 벗어날 때 확장하여 더하기 전체를 ​​읽을 수 있습니다. end iterator가 역방향으로 이동하는 데 사용되면이 파일을 처리해야합니다. 여기에 확실히 앞으로 파일을 읽을 수있는 코드와 역방향하지만 철저하게 테스트되지 않습니다

#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

"잘못된 방향으로 파일을 가로 지르면, 내 요구 사항에 대한 질문부터 시작하겠습니다. * "이것은 OP의 직접 요구 사항이 아니라 [Boost.Xpressive] (http://www.boost.org/libs/xpressive/)의 요구 사항입니다. – ildjarn

+0

그러면 원래 작성자는 다음과 같습니다. 잘못된 일에 Boost.Xpressive 사용하기! 잘못된 방향으로 파일을 읽는 것이 너무 효율적이지는 않습니다. 일부 라이브러리에 사용되는지 여부는 요점 외에도 전적으로 파일 뒷면을 읽어야합니다. 잘못된 주문이있는 것 같고 필요한 것이라고 질문 할 것입니다. –

+3

파일 내용에 대한 정규식을 실행하는 것은 이상하게 들릴 수 없습니다. 정규식에 대한 입력으로 파일 스트림을 사용하는 것은 잘못된 방법 일 수 있습니다. 전반적인 목표는 분명히 아니오입니다. 의심 스럽다. – ildjarn

3

당신은 같은 file.data()를 사용할 수 boost::iostreams::mapped_file_sourcehttp://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/mapped_file.html#mapped_file_source

한 번 봐 걸릴 끝 반복자로 반복자 및 file.data() + file.size()를 시작 .

+0

나는 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

Er, make_iterator_range가 포인터 쌍에서 reverse_copy를 수행 할 수 있기 전에 가장 좋은 예는 아니 었습니다. – Cubbi