文件/ifstream 上的双向迭代器 [英] bidirectional iterator over file/ifstream

查看:25
本文介绍了文件/ifstream 上的双向迭代器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一个具有双向迭代器/适配器的输入文件流.

I need an input file stream which would have a bidirectional iterator/adapter.

不幸的是,std::ifstream(和类似的)只能与 std::istream_iterator 一起使用,它是一种不能后退的前向迭代器.(还是我在这里弄错了?)

Unfortunately std::ifstream (and similar) can be used only with std::istream_iterator which is a kind of forward iterator which cannot go backwards. (or am I mistaken here?)

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

I could simply load the whole file to memory and then use a much more powerful random-access iterator over the array; however I would like to avoid that, and read only as much as I really need. It may happen that I really need only a small portion of a file.

我可以使用 C stdio.h 函数以某种方式手动完成,但这会很痛苦.我基本上需要手动实现一个双向迭代器,并记住它的所有规范.

I could somehow do it manually using C stdio.h functions, but that will be painful. I would basically need to implement a bidirectional iterator, with all its specification in mind, by hand.

我正在考虑研究 boost iostream 库,但手册有点不知所措,我希望有人能帮我实现这个特定的目标?或者也许有另一个已经存在的库可以完全满足我的需要?

I am considering looking into boost iostream library, but the manual is somewhat overwhelming, I was hoping someone could give me a hand to achieve this particular goal? Or maybe there is another already existing library to do exactly what I need?

我需要 boost xpressive 库的迭代器来解析我的文件,它期望迭代器可以递增也可以递减.如果我正在读取的文件被缓冲,我会很好,尽管这不是必需的.

I need the iterator for the boost xpressive library to parse my files, which expects that the iterator can be incremented as well as decremented. I would be fine if the file I am reading is buffered, although this is not a requirement.

有什么想法吗?谢谢!

推荐答案

如果我以错误的方向遍历文件,我会开始质疑我的要求.这似乎是一种人为的做事方式,很可能在某处发生了戏剧性的混乱.

If I were to traverse a file in the wrong direction, I would start off questioning my requirements. This seems to be a contrived way to do things and most likely something got messed up dramatically somewhere.

一旦我确认这确实是要求,我就会意识到我们在这里肯定是在谈论文件,而不是例如命名管道或套接字.也就是说,有可能内存映射文件的至少一部分.我会用它来创建一个遍历内存的迭代器.由于显然需要迭代器,因此无需涉及流.如果也需要流,我仍然会在自定义流缓冲区中内存映射文件和反向缓冲区.

Once I confirmed that this is indeed the requirement I would realize that we are definitely talking files here, rather than e.g. a named pipe or a socket. That is, it would be possible memory map at least parts of the file. I would use this to create an iterator which walks the memory. Since obviously an iterator is needed, there is no need to involve streams. If streams were needed too, I would still memory map the file and reverse buffers from the back in a custom stream buffer.

当实际从头开始读取并且只需要能够在必要时向后移动时,它可能比这更简单:保留已读取数据的缓冲区并在移动结束时扩展它并可能读取整个文件如果结束迭代器用于向后移动应该解决这个问题.下面的代码当然可以向前和向后读取文件,但没有经过彻底测试:

When actually reading from the start and just needing to be able to move backwards when necessary, it may be simpler than this: keeping a buffer of the already read data and expending it when moving off the end plus possibly reading the entire file if the end iterator is used to move backwards should address this. Here is code which certainly can read a file forward and backward but isn't thoroughly tested:

#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() 方法实际访问它.

Just create a bidirectional_stream with the stream you want to read as an argument and then use the begin() and end() methods to actually access it.

这篇关于文件/ifstream 上的双向迭代器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆