文件/ ifstream上的双向迭代器

时间:2012-01-26 22:58:08

标签: c++ boost iostream

我需要一个输入文件流,它有一个双向迭代器/适配器。

不幸的是std::ifstream(和类似的)只能用于std::istream_iterator,这是一种不能倒退的前向迭代器。 (或者我错了吗?)

我可以简单地将整个文件加载到内存中,然后在数组上使用更强大的随机访问迭代器;但是我想避免这种情况,并且只阅读我真正需要的内容。我可能只需要一小部分文件。

我可以使用C stdio.h函数以某种方式手动完成,但这将是痛苦的。我基本上需要手工实现一个双向迭代器,并考虑到所有规范。

我正在考虑调查boost iostream库,但手册有点压倒性,我希望有人可以帮我实现这一特定目标?或者也许还有另一个已经存在的库可以完全满足我的需求?

我需要boost xpressive库的迭代器来解析我的文件,它希望迭代器可以递增和递减。如果我正在阅读的文件被缓冲,我会没事的,虽然这不是必需的。

有什么想法吗? 谢谢!

2 个答案:

答案 0 :(得分: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());
}

只需使用您想要作为参数读取的流创建bidirectional_stream,然后使用begin()end()方法实际访问它。

答案 1 :(得分:3)

由于您已经在使用提升功能,请查看boost::iostreams::mapped_file_source http://www.boost.org/doc/libs/release/libs/iostreams/doc/classes/mapped_file.html#mapped_file_source

您可以使用file.data()作为开始迭代器,使用file.data()+ file.size()作为结束迭代器。