【问题标题】:Is it possible to use std::basic_ifstream and std::basic_ofstream with a custom buffer?是否可以将 std::basic_ifstream 和 std::basic_ofstream 与自定义缓冲区一起使用?
【发布时间】:2018-09-09 16:19:22
【问题描述】:

我不知道,是否可以将 std::basic_ifstream 和 std::basic_ofstream 与 std::basic_filebuf 的自定义实现一起使用?

按 64KB 大小的块读取文件并在内部检查块的某些哈希值的输入文件流的实现有多复杂?例如,如果哈希无效,则会抛出 corruption_exception。输出文件流在其后写入块和哈希值。

我找到了一些创建 std::ifstream 的示例,然后创建另一个从中读取并进行额外处理的流:

std::ifstream infile("test.img");
decompress_stream in(infile, 288);
char data[144 * 128];
in.read(data, 144 * 128);
infile.close();

但起初我希望它应该是这样的(没有额外的流):

std::ifstrem in;
in.setbuffer(new MyBuffer());
in.read();

MyBuffer::underflow()
{
     //read from original buffer
     if (hash != calculated_sash) throw curruption_exception();
     //return the data with omitted hash.
}

这可能吗?

【问题讨论】:

  • 不使用外部库的方法是从std::basic_filebuf 派生一个类,并使用该类型的对象作为basic_istream 的缓冲区。

标签: c++


【解决方案1】:

文件流对象实际上是std::basic_filebufstd::basic_[io]stream 的组合。流接口允许通过rdbuf() 方法访问std::basic_streambuf。因此,您可以将文件流流缓冲区替换为另一个。但是,它与原始文件缓冲区没有任何关系。

由于您拥有的流缓冲区是过滤流缓冲区,因此使用流构造它并让构造函数注入过滤器可能是合理的,即类似这样的东西(我省略了模板,因为这些与此无关讨论,但可以很容易地添加):

class filterbuf
    : public std::streambuf {
    std::istream* istream = nullptr;
    std::ostream* ostream = nullptr;
    std::streambuf * sbuf;

    // override virtual functions as needed
public:
    explicit filterbuf(std::istream& in)
        : istream(&in)
        , sbuf(istream->rdbuf(this)) {
    }
    explict filterbuf(std::ostream& out)
        : ostream(&out)
        , sbuf(ostream->rdbuf(this)) {
    }
    explicit filebuf(std::iostream& inout)
        : istream(&inout)
        , sbuf(istream->rdbuf(this)) {
    }
    ~filebuf() {
        istream && istream->rdbuf(sbuf);
        ostream && ostream->rdbuf(sbuf);
    }
};

在析构函数中恢复流缓冲区的要点是std::ostream析构函数在对象上调用flush(),此时自定义的流缓冲区已经消失了。

过滤器会这样使用:

std::istream fin(“whatever”);
filterbuf        buf(fin);
if (fin >> whatever) {
    ...
}

【讨论】:

    【解决方案2】:

    如果您想自定义 iostreams 的行为,最简单的方法是使用boost::iostreams。您的用例可能实现为InputfilterOutputFilter,您可以使用basic_file_sourcebasic_file_sink 来读取和写入文件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 2012-01-01
      • 1970-01-01
      • 2013-07-11
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      相关资源
      最近更新 更多