C++ 如何使用zlib压缩缓冲区?

C++ 如何使用zlib压缩缓冲区?,c++,compression,zlib,C++,Compression,Zlib,zlib网站上有一个使用示例: 然而,在这个例子中,他们正在压缩一个文件。我想压缩存储在内存缓冲区中的二进制数据。我也不想将压缩的缓冲区保存到磁盘 基本上这是我的缓冲区: fIplImageHeader->imageData = (char*)imageIn->getFrame(); 我如何用zlib压缩它 我希望能提供一些代码示例来说明如何做到这一点。这不是对您关于zlib API的问题的直接回答,但您可能对与zlib搭配的boost::iostreams库感兴趣 这允许使用基本

zlib网站上有一个使用示例:

然而,在这个例子中,他们正在压缩一个文件。我想压缩存储在内存缓冲区中的二进制数据。我也不想将压缩的缓冲区保存到磁盘

基本上这是我的缓冲区:

fIplImageHeader->imageData = (char*)imageIn->getFrame();
我如何用zlib压缩它

我希望能提供一些代码示例来说明如何做到这一点。

这不是对您关于zlib API的问题的直接回答,但您可能对与
zlib
搭配的
boost::iostreams
库感兴趣


这允许使用基本的“流”操作表示法使用
zlib
驱动的打包算法,然后通过打开一些内存流并执行
可以轻松地压缩数据。您可以通过使用指向数据的直接指针替换
fread()
fwrite()
调用来轻松地调整示例。对于zlib压缩(称为deflate,因为您“去掉了数据中的所有空气”),分配
z_stream
结构,调用
deflateInit()
,然后:

  • 用要压缩的下一块数据填充
    next_in
  • avail\u in
    设置为
    next\u in
  • next\u out
    设置为压缩数据应该写入的位置,压缩数据通常应该是缓冲区中的指针,随着时间的推移而前进
  • avail\u out
    设置为
    next\u out
  • 调用
    deflate
  • 重复步骤3-5,直到
    avail\u out
    为非零(即输出缓冲区中的空间大于zlib需要的空间-无需写入更多数据)
  • 有数据要压缩时,重复步骤1-6
  • 最后调用
    deflateEnd()
    ,就完成了


    你基本上是在给它输入和输出块,直到输入和输出都用完。

    这是一个用zlib打包缓冲区并将压缩内容保存在向量中的示例

    void compress_memory(void *in_data, size_t in_data_size, std::vector<uint8_t> &out_data)
    {
     std::vector<uint8_t> buffer;
    
     const size_t BUFSIZE = 128 * 1024;
     uint8_t temp_buffer[BUFSIZE];
    
     z_stream strm;
     strm.zalloc = 0;
     strm.zfree = 0;
     strm.next_in = reinterpret_cast<uint8_t *>(in_data);
     strm.avail_in = in_data_size;
     strm.next_out = temp_buffer;
     strm.avail_out = BUFSIZE;
    
     deflateInit(&strm, Z_BEST_COMPRESSION);
    
     while (strm.avail_in != 0)
     {
      int res = deflate(&strm, Z_NO_FLUSH);
      assert(res == Z_OK);
      if (strm.avail_out == 0)
      {
       buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
       strm.next_out = temp_buffer;
       strm.avail_out = BUFSIZE;
      }
     }
    
     int deflate_res = Z_OK;
     while (deflate_res == Z_OK)
     {
      if (strm.avail_out == 0)
      {
       buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE);
       strm.next_out = temp_buffer;
       strm.avail_out = BUFSIZE;
      }
      deflate_res = deflate(&strm, Z_FINISH);
     }
    
     assert(deflate_res == Z_STREAM_END);
     buffer.insert(buffer.end(), temp_buffer, temp_buffer + BUFSIZE - strm.avail_out);
     deflateEnd(&strm);
    
     out_data.swap(buffer);
    }
    
    void compress_内存(void*in_数据,size_t in_数据,std::vector&out_数据)
    {
    向量缓冲区;
    const size\u t BUFSIZE=128*1024;
    uint8临时缓冲区[BUFSIZE];
    z_溪strm;
    strm.zalloc=0;
    strm.zfree=0;
    strm.next_in=重新解释(输入数据);
    strm.avail\u in=in\u数据大小;
    strm.next_out=临时缓冲区;
    strm.avail\u out=BUFSIZE;
    deflateInit(&strm,Z_最佳压缩);
    while(strm.avail_in!=0)
    {
    int res=放气(&strm,Z_NO_FLUSH);
    断言(res==Z_OK);
    如果(strm.avail\u out==0)
    {
    buffer.insert(buffer.end(),temp\u buffer,temp\u buffer+BUFSIZE);
    strm.next_out=临时缓冲区;
    strm.avail\u out=BUFSIZE;
    }
    }
    int deflate_res=Z_OK;
    while(deflate_res==Z_OK)
    {
    如果(strm.avail\u out==0)
    {
    buffer.insert(buffer.end(),temp\u buffer,temp\u buffer+BUFSIZE);
    strm.next_out=临时缓冲区;
    strm.avail\u out=BUFSIZE;
    }
    放气=放气(&strm,Z_完成);
    }
    断言(deflate_res==Z_STREAM_END);
    buffer.insert(buffer.end()、temp\u buffer、temp\u buffer+BUFSIZE-strm.avail\u out);
    通货紧缩(strm);
    输出数据交换(缓冲区);
    }
    
    zlib.h
    具有您需要的所有功能:
    压缩
    (或
    压缩2
    )和
    解压缩
    。有关答案,请参阅zlib的源代码

    ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen, const Bytef *source, uLong sourceLen));
    /*
             Compresses the source buffer into the destination buffer.  sourceLen is
         the byte length of the source buffer.  Upon entry, destLen is the total size
         of the destination buffer, which must be at least the value returned by
         compressBound(sourceLen).  Upon exit, destLen is the actual size of the
         compressed buffer.
    
             compress returns Z_OK if success, Z_MEM_ERROR if there was not
         enough memory, Z_BUF_ERROR if there was not enough room in the output
         buffer.
    */
    
    ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen, const Bytef *source, uLong sourceLen));
    /*
             Decompresses the source buffer into the destination buffer.  sourceLen is
         the byte length of the source buffer.  Upon entry, destLen is the total size
         of the destination buffer, which must be large enough to hold the entire
         uncompressed data.  (The size of the uncompressed data must have been saved
         previously by the compressor and transmitted to the decompressor by some
         mechanism outside the scope of this compression library.) Upon exit, destLen
         is the actual size of the uncompressed buffer.
    
             uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
         enough memory, Z_BUF_ERROR if there was not enough room in the output
         buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.  In
         the case where there is not enough room, uncompress() will fill the output
         buffer with the uncompressed data up to that point.
    */
    

    <强>经典方式,C++特性<<强> < /p> 下面是一个完整的示例,演示了使用

    C++
    std::vector
    对象进行压缩和解压缩:

    #include <cstdio>
    #include <iosfwd>
    #include <iostream>
    #include <vector>
    #include <zconf.h>
    #include <zlib.h>
    #include <iomanip>
    #include <cassert>
    
    void add_buffer_to_vector(std::vector<char> &vector, const char *buffer, uLongf length) {
        for (int character_index = 0; character_index < length; character_index++) {
            char current_character = buffer[character_index];
            vector.push_back(current_character);
        }
    }
    
    int compress_vector(std::vector<char> source, std::vector<char> &destination) {
        unsigned long source_length = source.size();
        uLongf destination_length = compressBound(source_length);
    
        char *destination_data = (char *) malloc(destination_length);
        if (destination_data == nullptr) {
            return Z_MEM_ERROR;
        }
    
        Bytef *source_data = (Bytef *) source.data();
        int return_value = compress2((Bytef *) destination_data, &destination_length, source_data, source_length,
                                     Z_BEST_COMPRESSION);
        add_buffer_to_vector(destination, destination_data, destination_length);
        free(destination_data);
        return return_value;
    }
    
    int decompress_vector(std::vector<char> source, std::vector<char> &destination) {
        unsigned long source_length = source.size();
        uLongf destination_length = compressBound(source_length);
    
        char *destination_data = (char *) malloc(destination_length);
        if (destination_data == nullptr) {
            return Z_MEM_ERROR;
        }
    
        Bytef *source_data = (Bytef *) source.data();
        int return_value = uncompress((Bytef *) destination_data, &destination_length, source_data, source.size());
        add_buffer_to_vector(destination, destination_data, destination_length);
        free(destination_data);
        return return_value;
    }
    
    void add_string_to_vector(std::vector<char> &uncompressed_data,
                              const char *my_string) {
        int character_index = 0;
        while (true) {
            char current_character = my_string[character_index];
            uncompressed_data.push_back(current_character);
    
            if (current_character == '\00') {
                break;
            }
    
            character_index++;
        }
    }
    
    // https://stackoverflow.com/a/27173017/3764804
    void print_bytes(std::ostream &stream, const unsigned char *data, size_t data_length, bool format = true) {
        stream << std::setfill('0');
        for (size_t data_index = 0; data_index < data_length; ++data_index) {
            stream << std::hex << std::setw(2) << (int) data[data_index];
            if (format) {
                stream << (((data_index + 1) % 16 == 0) ? "\n" : " ");
            }
        }
        stream << std::endl;
    }
    
    void test_compression() {
        std::vector<char> uncompressed(0);
        auto *my_string = (char *) "Hello, world!";
        add_string_to_vector(uncompressed, my_string);
    
        std::vector<char> compressed(0);
        int compression_result = compress_vector(uncompressed, compressed);
        assert(compression_result == F_OK);
    
        std::vector<char> decompressed(0);
        int decompression_result = decompress_vector(compressed, decompressed);
        assert(decompression_result == F_OK);
    
        printf("Uncompressed: %s\n", uncompressed.data());
        printf("Compressed: ");
        std::ostream &standard_output = std::cout;
        print_bytes(standard_output, (const unsigned char *) compressed.data(), compressed.size(), false);
        printf("Decompressed: %s\n", decompressed.data());
    }
    
    产出:

    Uncompressed: Hello, world!
    Compressed: 78daf348cdc9c9d75128cf2fca495164000024e8048a
    Decompressed: Hello, world!
    
    推进方式

    #include <iostream>
    #include <boost/iostreams/filtering_streambuf.hpp>
    #include <boost/iostreams/copy.hpp>
    #include <boost/iostreams/filter/zlib.hpp>
    
    std::string compress(const std::string &data) {
        boost::iostreams::filtering_streambuf<boost::iostreams::output> output_stream;
        output_stream.push(boost::iostreams::zlib_compressor());
        std::stringstream string_stream;
        output_stream.push(string_stream);
        boost::iostreams::copy(boost::iostreams::basic_array_source<char>(data.c_str(),
                                                                          data.size()), output_stream);
        return string_stream.str();
    }
    
    std::string decompress(const std::string &cipher_text) {
        std::stringstream string_stream;
        string_stream << cipher_text;
        boost::iostreams::filtering_streambuf<boost::iostreams::input> input_stream;
        input_stream.push(boost::iostreams::zlib_decompressor());
    
        input_stream.push(string_stream);
        std::stringstream unpacked_text;
        boost::iostreams::copy(input_stream, unpacked_text);
        return unpacked_text.str();
    }
    
    TEST_CASE("zlib") {
        std::string plain_text = "Hello, world!";
        const auto cipher_text = compress(plain_text);
        const auto decompressed_plain_text = decompress(cipher_text);
        REQUIRE(plain_text == decompressed_plain_text);
    }
    
    #包括
    #包括
    #包括
    #包括
    std::字符串压缩(const std::字符串和数据){
    boost::iostreams::过滤输出流;
    output_stream.push(boost::iostreams::zlib_compressor());
    std::stringstream字符串\u流;
    输出\u流.push(字符串\u流);
    boost::iostreams::copy(boost::iostreams::basic_array_source(data.c_str()),
    data.size()),输出(U流);
    返回字符串_stream.str();
    }
    字符串解压缩(常量std::字符串和密码文本){
    std::stringstream字符串\u流;
    
    string\u stream您提到的示例有什么问题?它确实会压缩内存中的缓冲区,只是它首先从文件中读取数据。您从其他地方获取数据,但其余的都是一样的-为什么不是?+1。如果您需要所有默认设置,这是一个非常简单的解决方案。即使您不需要默认设置,也可以修改和删除使用这些函数的源代码。不幸的是,在使用uncompress()之前我们必须知道未压缩数据的大小才能分配缓冲区。如果您以前在压缩数据时没有保存该大小,那就太倒霉了。只是一个注释,但这意味着您必须包含boost iostreams库、boost zlib库、libz和libzbz2,而不是仅包含libz。因此,如果捆绑这些库是一个问题大小问题那么在这种情况下最好避免boost。~BenI刚刚读了一个有趣的方法,它使用一个标志来控制刷新状态,并在一个循环中完成。另外,值得注意的是,这同样适用于std::string而不是向量,这很适合通过线路发送或发送到另一个函数。这看起来非常复杂d、 为什么要这样做而不是仅仅使用
    compress
    函数呢?compress要求您知道输出大小并分配足够大的缓冲区;此方法允许您realloc()并且有一个动态扩展的缓冲区。很好的代码,但是
    temp\u buffer
    会产生一个
    转义本地作用域的警告3次。您可能需要修复这个问题。请注意
    uLongf destination\u length=compressBound(source\u length);char destination\u data[destination\u length]不是有效的C++。它没有VLA.@ HOLYBLASCAT:但是代码没有警告,代码< C++ 17 > /代码> @ HyyBrask:好的,我将使用<代码>
    
    #include <iostream>
    #include <boost/iostreams/filtering_streambuf.hpp>
    #include <boost/iostreams/copy.hpp>
    #include <boost/iostreams/filter/zlib.hpp>
    
    std::string compress(const std::string &data) {
        boost::iostreams::filtering_streambuf<boost::iostreams::output> output_stream;
        output_stream.push(boost::iostreams::zlib_compressor());
        std::stringstream string_stream;
        output_stream.push(string_stream);
        boost::iostreams::copy(boost::iostreams::basic_array_source<char>(data.c_str(),
                                                                          data.size()), output_stream);
        return string_stream.str();
    }
    
    std::string decompress(const std::string &cipher_text) {
        std::stringstream string_stream;
        string_stream << cipher_text;
        boost::iostreams::filtering_streambuf<boost::iostreams::input> input_stream;
        input_stream.push(boost::iostreams::zlib_decompressor());
    
        input_stream.push(string_stream);
        std::stringstream unpacked_text;
        boost::iostreams::copy(input_stream, unpacked_text);
        return unpacked_text.str();
    }
    
    TEST_CASE("zlib") {
        std::string plain_text = "Hello, world!";
        const auto cipher_text = compress(plain_text);
        const auto decompressed_plain_text = decompress(cipher_text);
        REQUIRE(plain_text == decompressed_plain_text);
    }