0

我正在实现自己的 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_;
};

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

让我们只看ogzstream's 的实现。

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;
}

所以,问题是tellp()对我自己实现的ogzstream对象(ogzstreambuf内部保存一个实例)的调用返回-1(EOF)值,因为:

在内部,如果成员失败返回 true,则函数返回 -1。否则,它返回rdbuf()->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()返回EOFtellp()失败。我想了解我在实施过程中遗漏了什么,以及我应该做些什么来改善这种认识。

4

1 回答 1

0

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

于 2016-06-10T07:26:00.443 回答