如何使用 boost iostreams 流式解压

Tak*_*ndo 3 c++ boost zlib 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] = { '\0' };
#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;

}
Run Code Online (Sandbox Code Playgroud)

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

read_size:0
rdstate:0
Run Code Online (Sandbox Code Playgroud)

这对我来说是出乎意料的。

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

rdstate:2
Hello World
Run Code Online (Sandbox Code Playgroud)

这是预期的输出。

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

有什么办法来使用readsome()具有filtering_streambuf或没有什么好的办法来解压缩流长不可预知的二进制数据?

Tak*_*ndo 5

感谢sehe的评论,问题解决了。

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

我换了

std::size_t read_size = is.readsome(buf, buf_size);
Run Code Online (Sandbox Code Playgroud)

is.read(buf, buf_size);
std::size_t read_size = is.gcount();
Run Code Online (Sandbox Code Playgroud)

,那么问题就解决了。

std::istream::read读取buf_size长度数据之前,我误解了那个块。这不是真的。即使实际读取大小小于 buf_size,函数也会返回。请参阅http://www.cplusplus.com/reference/istream/istream/read/。为了得到read_size,我打电话std::istream::gcount()。请参阅http://www.cplusplus.com/reference/istream/istream/gcount/

注意:我对boost::asio::read和感到困惑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] = { '\0' };
    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;

}
Run Code Online (Sandbox Code Playgroud)