如何使用 boost iostreams 进行流式解压缩

How to streaming decompress using boost iostreams

我正在使用 boost iostreams (1.64.0) 来解压缩 zlib 数据。 我想做流式解压。这意味着压缩数据的大小不可预测。 我写了下面的代码示例。

#include <sstream>
#include <string>
#include <iostream>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>

int main() {
    // Compress
    std::stringstream sender;
    boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
    out.push(boost::iostreams::zlib_compressor());
    out.push(sender);
    sender << "Hello World";
    std::stringstream compressed;
    boost::iostreams::copy(out, compressed);

    // Decompress
    boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
    in.push(boost::iostreams::zlib_decompressor());
    in.push(compressed);
    std::istream is(&in);
    std::size_t const buf_size = 256;
    char buf[buf_size] = { '[=10=]' };
#if 0
    is.getline(buf, buf_size); // works fine
#else
    std::size_t read_size = is.readsome(buf, buf_size);
    std::cout << "read_size:" << read_size << std::endl;
#endif
    // http://www.cplusplus.com/reference/ios/ios/rdstate/
    std::cout << "rdstate:" << is.rdstate() << std::endl;
    std::cout << buf << std::endl;

}

我使用readsome()因为数据的大小是不可预测的。 我得到以下输出:

read_size:0
rdstate:0

出乎我的意料。

如果我使用 getline() 而不是 readsome(),我得到以下输出:

rdstate:2
Hello World

这是预期的输出。

我想当我使用readsome()时,输出应该是一样的。 我无法在实际代码中使用 getline() 我的,因为原始数据是二进制格式。

有什么方法可以将 readsome()filtering_streambuf 一起使用,或者有什么好的方法可以流式解压缩不可预测长度的二进制数据吗?

感谢,问题解决

我为评论写了,但很难阅读,因为代码格式不正确。所以我自己回答。希望对其他遇到类似问题的人有所帮助。

我替换了

std::size_t read_size = is.readsome(buf, buf_size);

is.read(buf, buf_size);
std::size_t read_size = is.gcount();

,问题解决

我误解了 std::istream::read 块直到读取 buf_size 长度数据。这不是真的。即使实际读取大小小于buf_size,函数returns。参见 http://www.cplusplus.com/reference/istream/istream/read/. In order to get read_size, I call std::istream::gcount(). See http://www.cplusplus.com/reference/istream/istream/gcount/

注意:我对 boost::asio::read and boost::asio::ip::tcp::socket::read_some 感到困惑。但他们的行为与std::istream的不同。

修复版的完整代码如下:

#include <sstream>
#include <string>
#include <iostream>

#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/zlib.hpp>

int main() {
    // Compress
    std::stringstream sender;
    boost::iostreams::filtering_streambuf<boost::iostreams::input> out;
    out.push(boost::iostreams::zlib_compressor());
    out.push(sender);
    sender << "Hello World";
    std::stringstream compressed;
    boost::iostreams::copy(out, compressed);

    // Decompress
    boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
    in.push(boost::iostreams::zlib_decompressor());
    in.push(compressed);
    std::istream is(&in);
    std::size_t const buf_size = 256;
    char buf[buf_size] = { '[=12=]' };
    is.read(buf, buf_size);
    std::size_t read_size = is.gcount();
    std::cout << "read_size:" << read_size << std::endl;
    // http://www.cplusplus.com/reference/ios/ios/rdstate/
    std::cout << "rdstate:" << is.rdstate() << std::endl;
    std::cout << buf << std::endl;

}