【问题标题】:Problems with writing a custom streambuf for gzipped streams为 gzip 流编写自定义 streambuf 的问题
【发布时间】:2016-06-09 14:01:54
【问题描述】:

我正在实现自己的 streambuf 类来编写压缩输出文件。 这是它的样子。

template <class T>
class gzstreambufbase : public std::streambuf
{
protected:
    static const int bufferSize = 8192;

public:
    gzstreambufbase();
    ~gzstreambufbase();

    bool close();
    bool is_open();

protected:
    virtual T* open(const std::string& name, std::ios::openmode mode) = 0;
    virtual int sync();

    // flush the characters in the buffer
    int flush_buffer();

protected:
    gzFile             filePtr_;
    std::ios::openmode mode_;
    bool               opened_;
    char               buffer_[bufferSize];
    std::string        fileName_;
};

然后我从这个基本的新igzstreambufogzstreambuf 类派生相应的输入和输出流缓冲区。 基本上,实现是按照 Nicolai M. Josuttis [C++ 标准库,The: A Tutorial and Reference] 一书中的示例完成的。

让我们只看ogzstream 的实现。

ogzstreambuf::ogzstreambuf()
{
    // initialize data buffer
    // one character less to let the bufferSizeth
    // character cause a call of overflow()
    setp( buffer_, buffer_ + (bufferSize - 1));
}

ogzstreambuf*
ogzstreambuf::open(const std::string& name, std::ios::openmode mode)
{
    if (is_open())
        return (ogzstreambuf*)0;

    mode_ = mode;
    fileName_ = name;

    filePtr_ = gzopen(fileName_.c_str(), "wb");
    CUSTOM_CHECK(0 != filePtr_, ("GZIP_IO_ERROR", strerror(errno)));
    opened_ = 1;

    return this;
}

std::streampos
ogzstreambuf::seekpos(std::streampos offset, std::ios_base::openmode which)
{
    return seekImpl(offset, std::ios_base::beg, which);
}

std::streampos
ogzstreambuf::seekoff(std::streamoff offset, std::ios_base::seekdir way, std::ios_base::openmode which)
{
    return seekImpl(offset, way, which);
}

std::streampos
ogzstreambuf::seekImpl(std::streamoff offset, std::ios_base::seekdir way, std::ios_base::openmode which)
{
    assert(!fileName_.empty(), "");
    assert(LONG_MAX != offset, "");
    assert(std::ios_base::out == which, "");
    assert( way != std::ios_base::end,
                 "zlib doesn't support the value SEEK_END in gzseek()." );

    if (!flush_buffer())
        return std::streampos(EOF);

    const long newPos = gzseek(filePtr_, offset,
                              (way == std::ios_base::beg ? SEEK_SET : SEEK_CUR));

    CUSTOM_CHECK((long) offset == newPos, ("GZIP_IO_ERROR", strerror(errno)));
    setp(buffer_, buffer_ + (bufferSize - 1));

    return offset;
}

所以,问题在于对我自己实现的ogzstream 对象(内部包含ogzstreambuf 的实例)的tellp() 调用返回-1(EOF) 值,因为:

在内部,如果成员失败返回 true,则函数返回 -1。 否则返回rdbuf()-&gt;pubseekoff(0,cur,out);

引自cpp。 最后flush_buffer() 返回0 因为pptr() - pbase(); 等于0

template <class T>
int gzstreambufbase<T>::flush_buffer()
{
    // Separate the writing of the buffer from overflow() and
    // sync() operation.
    int w = pptr() - pbase();
    if ( gzwrite( filePtr_, pbase(), w) != w)
        return EOF;

    pbump( -w); // reset put pointer acccordingly
    return w;
}

因此,pubseekoff() 返回 EOF 并且 tellp() 失败。 我想了解我在实施过程中遗漏了什么以及我应该如何改进这一认识。

【问题讨论】:

  • 如果您还不熟悉,不妨看看 boost io_streams 工具,有一个压缩流可以添加到管道中进行读/写 - 这是一个不错的方法..跨度>
  • @Nim,实际上我已经尝试实现类似于 boost_io_streams 的东西(使用管道)。这是我的另一个问题:link
  • @Nim,顺便说一句,我需要一个可搜索的 gzip 流,正如我在 boost::iostreams 中所知道的那样,filtering_stream&lt;output_seekable&gt; 不适用于 gzip_compressor() :)
  • 我不知道,以前从不需要那个..

标签: c++ gzip streambuf


【解决方案1】:

经过适当的调试,我自己终于找到了问题所在。只需要检查EOF == flush_buffer() 而不是!flush_buffer()...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-30
    • 2021-05-30
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    相关资源
    最近更新 更多