【问题标题】:Compressing/decompressing gzip into memory with boost使用 boost 将 gzip 压缩/解压缩到内存中
【发布时间】:2014-02-21 19:41:42
【问题描述】:

我会简短:我有这段代码:

QByteArray MyNBT::decompressData(QByteArray data)
{
    filtering_streambuf<input> in;

    std::string _data = data.data();

    in.push( gzip_decompressor() );
    in.push( boost::iostreams::back_inserter(_data) );
    //in.push( std::back_inserter(_data) );

    std::stringstream _sstream;
    boost::iostreams::copy(in, _sstream);

    QByteArray out = _sstream.rdbuf()->str().c_str();

    return out;
}

它在这一行给出了一个错误:

in.push( boost::iostreams::back_inserter(_data) );
//in.push( std::back_inserter(_data) );

错误是:

/usr/include/boost/iostreams/chain.hpp:244: error: invalid application of 'sizeof' to incomplete type 'boost::STATIC_ASSERTION_FAILURE<false>'
     BOOST_STATIC_ASSERT((is_convertible<category, Mode>::value));
     ^

编译器在std::back_inserter(_data) 中抛出此错误一次,在 boost 中抛出两次。

提前致谢。

【问题讨论】:

    标签: c++ boost gzip boost-iostreams


    【解决方案1】:

    back_inserter 做什么?

    确实如此。它在容器的后面插入元素。

    不过,您似乎追求的是front_readercontainer_source

    好吧,我没有 Qt,但我很幸运使用 array_source 来调整您的输入(请注意它与 std::stringstd::vectorstd::array 甚至只是 const char [] 输入同样适用):

    #include <fstream>
    #include <iostream>
    
    #include <boost/iostreams/filtering_stream.hpp>
    #include <boost/iostreams/filter/gzip.hpp>
    #include <boost/iostreams/copy.hpp>
    #include <sstream>
    
    int main()  {
        using namespace boost::iostreams;
        filtering_streambuf<input> in;
    
    #if 0
        std::string _data { 
    #else
        std::vector<char> _data { 
    #endif
            char(0x1f), char(0x8b), char(0x08), char(0x00), char(0xca), char(0xb5),
            char(0x07), char(0x53), char(0x00), char(0x03), char(0xcb), char(0x48),
            char(0xcd), char(0xc9), char(0xc9), char(0x57), char(0x28), char(0xcf),
            char(0x2f), char(0xca), char(0x49), char(0xe1), char(0x02), char(0x00),
            char(0x2d), char(0x3b), char(0x08), char(0xaf), char(0x0c), char(0x00),
            char(0x00), char(0x00)
        };
    
        in.push( gzip_decompressor() );
        in.push( boost::iostreams::array_source(_data.data(), _data.size()) );
    
        std::stringstream _sstream;
        boost::iostreams::copy(in, _sstream);
    
        std::cout << _sstream.rdbuf();
    }
    

    程序的输出当然是hello world

    【讨论】:

    • 现在可以编译了,但是在运行时会抛出异常gzip error。我使用的 gzip 没问题。我已经尝试过您的代码,我制作的一些 gzip(并使用其他有效的示例进行了测试)...
    • 我假设您现在指的是您的代码,而不是我的(我测试过)。我只能猜测 zip 数据已损坏。也许您没有使用二进制流或在路上的某处遇到终止 NUL 字符
    • 我的代码将所有二进制文件读入一个字符串,在一些函数之间传递(不改变它),然后如果我将它标记为压缩,上面的函数解压缩它。很简单。
    • 是时候检查字符串中的数据是否仍然有序(异常告诉你它不是!)。也许将其写入另一个二进制文件并使用外部工具解压缩。证明有帮助
    • @azteca1998 我建议您尝试摆脱“巧合编程”的心态(“没人知道” - 呃。人们确实知道。样本没有错)。现在“只复制几个字节”完全是我在第一条评论中预测的:您通过自愿阻塞 NUL 字符来破坏输入数据。您只是不能将二进制数据视为 C 字符串。更不用说效率低下。
    【解决方案2】:

    使用@sehe 的回答修复它。

    这是生成的代码:(希望它对有同样错误的人有用)

    QByteArray MyNBT::decompressData(QByteArray data)
    {
        filtering_streambuf<input> in;
    
        std::vector<char> _data;
        foreach( char ch, data )
            _data.push_back(ch);
    
        in.push( gzip_decompressor() );
        in.push( boost::iostreams::array_source(_data.data(), _data.size()) );
    
        QByteArray out;
        while ( in.sgetc() != -1 )
            out += (unsigned char)in.sbumpc();
    
        std::cout << "out size! :: " << in.in_avail() << std::endl;
        //std::cout << "out size! :: " << _sstream.str().size() << std::endl;
        std::cout << "out size! :: " << out.size() << std::endl;
    
        return out;
    }
    

    【讨论】:

    • 看看std::copy_n 会更有效率。很可能,你甚至可以只使用std::vector&lt;char&gt; const _data(data.begin(), data.end());(注意 const),你应该可以使用std::vector&lt;char&gt; const _data(data.data(), data.size());,最后,为什么不直接使用array_source(data.data(), data.size()) 而无需复制?
    【解决方案3】:

    我也使用了一个简单的字符数组,为了效率,不想创建一个向量并复制缓冲区内容。所以,这是我对一个简单的 in-ram 压缩/解压缩实用程序类的看法,它直接从从线路读取的 char 数组解压缩或压缩到另一个 char 数组中:

    /*
     * GzipUtil.h
     *
     *  Created on: Nov 3, 2015
     *      Author: tprice
     */
    
    #ifndef GZIPUTIL_H_
    #define GZIPUTIL_H_
    
    #include <unistd.h>
    #include <stdint.h>
    #include <vector>
    #include <stdlib.h>
    
    #include <boost/iostreams/filtering_stream.hpp>
    #include <boost/iostreams/filter/gzip.hpp>
    
    namespace BIO = boost::iostreams;
    
    class GzipUtil {
    public:
    GzipUtil() {}
    virtual ~GzipUtil() {}
    
    static ssize_t compress(char *src, char *dest, ssize_t len)
    {
        ssize_t retval = 0;
    
        BIO::filtering_streambuf<BIO::input> in;
        in.push( BIO::gzip_compressor() );
        in.push( BIO::array_source(src, len) );
        for(retval = 0; in.sgetc() != -1; retval++ )
        {
            dest[retval] = (char) in.sbumpc();
        }
    
        return retval;
    }
    
    static ssize_t decompress(char *src, ssize_t srclen, std::vector<char*> & dest, ssize_t destChunkLen)
    {
        ssize_t retval = 0;
        char*   chunkPtr = NULL;
        ssize_t chunkUsed = 0;
    
        BIO::filtering_streambuf<BIO::input> in;
        in.push( BIO::gzip_decompressor() );
        in.push( BIO::array_source(src, srclen) );
        for(retval = 0; in.sgetc() != -1; retval++ )
        {
            if((chunkPtr == NULL) || (chunkUsed >= destChunkLen))
            {
                chunkPtr = (char*) malloc(destChunkLen);
                dest.push_back(chunkPtr);
                chunkUsed = 0;
            }
            chunkPtr[chunkUsed++] = (char) in.sbumpc();
        }
    
        return retval;
    }
    
    };
    
    
    #endif /* GZIPUTIL_H_ */
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-12
      • 2021-11-15
      • 2015-07-14
      相关资源
      最近更新 更多