c++ - zlib - gzip 的零压缩率

标签 c++ gzip zlib

我有以下使用 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() 不会,也不能被 deflate() 更改。您从 dest.size() 得到的只是压缩之前 输出缓冲区的大小。您需要查看从 deflate() 调用返回的东西,以确定压缩结果的大小。这可以是 dest.size() - strm.avail_outstrm.total_out

在单个调用中执行压缩意味着您需要将输入和输出缓冲区大小都放入 unsigned 中,通常为 32 位。因此,您只能压缩大约 4 GB 的数据。如果您可能需要做更多的事情,那么您将需要一个循环,为较小的 block 调用 deflate()。可能更小的 block ,以 10 或 100 千字节为单位。这是使用 deflate() 的常用方法,因为它占用的内存要少得多,并且可以防止您的例程成为这方面的资源消耗者。

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

关于c++ - zlib - gzip 的零压缩率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54027155/

相关文章:

javascript - 如何在 Amazon Beanstalk 和 Tomcat 上启用 HTML/JavaScript/CSS 的 gzip

javascript - 从因字符串长度而必须压缩的字符串创建可下载链接

c++ - 存储 8 个整数的 avx2 指令是什么?

c++ - 使用光流进行特征跟踪

amazon-web-services - Amazon AWS Athena HIVE_CANNOT_OPEN_SPLIT : Error opening Hive split/Not valid Parquet file, parquet 文件使用 Athena 压缩为 gzip

python - 安装 PIP Python 3.6.3 Ubuntu 16.04 Zlib 不可用,但已安装

node.js - NodeJS 流响应以防止内存不足错误

c++ - 意外行为字符串文字

c++ - std::set_intersection 用于排序的范围,因为 [ _] 用于未排序的范围/容器

.htaccess - 测试 gzip 是否在本地工作