zlib - Нулевая степень сжатия для gzip - PullRequest
0 голосов
/ 03 января 2019

У меня есть следующий код C ++, который использует zlib для сжатия буфера памяти в поток, закодированный в 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;
    }
}

Пока функция завершается успешно, я вообще не получаю сжатия.Фактически, для файла размером 3 МБ, состоящего только из символа «a», повторяющегося несколько раз, я получаю следующее:

Original: 3205841; compressed: 3206843

Я что-то не так делаю?

(Обратите внимание, что этоупрощенная версия исходного кода; на практике я буду использовать RAII и исключения для обработки ресурсов и ошибок).

1 Ответ

0 голосов
/ 04 января 2019

Комментарии к вопросу являются ответами, поэтому просто запишите их здесь для потомков ...

dest.size() нет и не может быть изменено с помощью deflate(). Все, что вы получаете от dest.size(), это размер буфера вывода до сжатия . Вам нужно взглянуть на что-то , которое возвращается из вызова deflate(), чтобы определить размер сжатого результата. Это может быть либо dest.size() - strm.avail_out, либо strm.total_out.

Выполнение сжатия за один вызов означает, что вам нужно уместить размер входного и выходного буфера в unsigned, который обычно составляет 32 бита. Таким образом, вы ограничены сжатием около 4 ГБ данных. Если вам может потребоваться сделать больше, вам понадобится цикл, вызывающий deflate() для небольших кусков. Возможно, намного меньшие куски, измеренные в 10 или 100 Кбайт. Это обычный способ использования deflate(), так как он занимает гораздо меньше памяти и не позволяет вашей рутине быть ресурсом в этом отношении.

deflateBound() специально для поддержки использования одного deflate() вызова. Он обеспечивает верхнюю границу для возможного сжатого размера, который может быть на больше , чем входные данные. Это тот случай, когда входные данные несжимаемы, например, уже сжатый или случайный.

...