【问题标题】:zlib - Zero compression rate for gzipzlib - gzip 的零压缩率
【发布时间】:2019-05-30 07:54:58
【问题描述】:

我有以下使用 zlib 压缩内存的 C++ 代码 缓冲成 gzip 编码流:

void compress(const std::vector<char>& src)
{
    static constexpr int DEFAULT_WINDOW_BITS = 15;
    static constexpr int GZIP_WINDOW_BITS = DEFAULT_WINDOW_BITS + 16;
    static constexpr int GZIP_MEM_LEVEL = 8;

    z_stream stream;

    const auto srcData = reinterpret_cast<unsigned char*>(const_cast<char*>(src.data()));

    stream.zalloc = Z_NULL;
    stream.zfree = Z_NULL;
    stream.opaque = Z_NULL;
    stream.next_in = srcData;
    stream.avail_in = src.size();

    auto result = deflateInit2(&stream,
                               Z_DEFAULT_COMPRESSION,
                               Z_DEFLATED,
                               GZIP_WINDOW_BITS,
                               GZIP_MEM_LEVEL,
                               Z_DEFAULT_STRATEGY);

    if (result == Z_OK)
    {
        std::vector<char> dest(deflateBound(&stream, stream.avail_in));
        const auto destData = reinterpret_cast<unsigned char*>(dest.data());

        stream.next_out = destData;
        stream.avail_out = dest.size();

        result = deflate(&stream, Z_FINISH);

        if (result == Z_STREAM_END)
        {
            std::cout << "Original: " << src.size() << "; compressed: " << dest.size() << std::endl;
        }
        else
        {
            std::cerr << "Error when compressing: code " << std::to_string(result);
        }

        result = deflateEnd(&stream);

        if (result != Z_OK)
        {
            std::cerr << "Error: Cannot destroy deflate stream: code " << std::to_string(result) << std::endl;
        }
    }
    else
    {
        std::cerr << "Error: Cannot initialize deflate stream: code " << std::to_string(result) << std::endl;
    }
}

虽然函数成功完成,但我没有得到压缩 一点也不。实际上,对于仅包含字符“a”的 3MB 文件 重复多次,我得到以下信息:

Original: 3205841; compressed: 3206843

我是不是做错了什么?

(请注意,这是原始代码的简化版本;实际上,我会使用 RAII 和异常来处理资源和错误)。

【问题讨论】:

  • 你为什么用dest.size()而不是stream.total_out
  • 哦,该死的......你是对的,这确实显示了更小的尺寸。但是,为什么 deflateBound 一开始就给出这么大的数字呢?
  • "deflateBound() 和 compressBound() 函数可用于提供扩展的上限,以允许分配确保足够大以容纳整个压缩输出的输出缓冲区。” - 上限 = 最坏情况
  • 如果您想查看最坏的情况,请使用随机或加密数据作为输入

标签: c++ gzip zlib


【解决方案1】:

问题上的cmets就是答案,所以在这里记录下来以备后人......

dest.size() 没有,也不能由deflate() 更改。您从dest.size() 得到的只是压缩前 输出缓冲区的大小。您需要查看从 deflate() 调用返回的 something 以确定压缩结果的大小。可以是dest.size() - strm.avail_out,也可以是strm.total_out

在一次调用中进行压缩意味着您需要在unsigned 中调整输入和输出缓冲区大小,通常为 32 位。因此,您只能压缩大约 4 GB 的数据。如果您可能需要做更多,那么您将需要一个循环,调用 deflate() 以获得较小的块。可能小得多的块,以 10 或 100 千字节为单位。这是使用deflate() 的常用方式,因为它占用的内存要少得多,并且在这方面您的例程不会占用资源。

deflateBound() 专门用于支持使用单个deflate() 调用。它提供了可能压缩大小的上限,该上限可能比输入数据一点。当输入数据不可压缩时就是这种情况,例如已经压缩或随机。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 2016-06-11
    • 2012-11-25
    • 1970-01-01
    相关资源
    最近更新 更多