如何使用Boost iostreams进行流解压缩

3

我正在使用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;

}

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

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

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

rdstate:2
Hello World

这是预期输出。

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

有没有办法在使用 filtering_streambuf 或者其他好的方法流式解压不确定长度的二进制数据时使用 readsome()


1
为什么不使用read()呢? - sehe
1
感谢您的评论。我意识到我误解了istream :: read()istream :: readsome()的行为,它们的行为类似于boost asioread()socket :: read_some()。我用以下代码进行了替换: `is.read(buf, buf_size);` `std::size_t read_size = is.gcount();` `std::cout << "read_size:" << read_size << std::endl;`然后我的代码就按照我预期的那样工作了。 - Takatoshi Kondo
1个回答

5

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

我为评论写了回复,但由于代码格式不好,很难阅读。所以我自己回答了。希望这能帮助其他遇到类似问题的人。

我替换了

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,该函数也会返回。请参见http://www.cplusplus.com/reference/istream/istream/read/。为了获取read_size,我调用std::istream::gcount()。请参见http://www.cplusplus.com/reference/istream/istream/gcount/

注意:我曾经混淆了 boost::asio::readboost::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;

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接