You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Zlib单字节分块解压报错Z_BUF_ERROR问题求助

分块解压Zlib数据时Z_BUF_ERROR问题排查与解决

问题描述

我有一个通过Zlib压缩的数据缓冲区,希望分块(每次1字节)完成解压,而非一次性分配足够大的输出缓冲区来容纳所有解压后的数据。参照zpipe.c的思路实现代码后,inflate始终抛出Z_BUF_ERROR错误,无法将数据解压到1字节缓冲区中。

原代码

#include <iostream>
#include <string>
#include <zlib.h>


static std::string in_buff_string;
static std::string out_buff_string;
static z_stream stream;



int my_uncompress_func__from_memory(unsigned long CHUNK_SIZE, char* char_p__to_compressed_data, unsigned long size__compressed_data)
{

    //char_p__to_compressed_data - buffer with compresed data
    //size__compressed_data      - size data in buffer "char_p__to_compressed_data "

    CHUNK_SIZE = 1;  //1 byte


    //-------------------------------------
    in_buff_string.resize(CHUNK_SIZE);           
    out_buff_string.resize(CHUNK_SIZE);         
    int err;
    //-------------------------------------

    stream = { 0 };


    //-------------------------------------
    err = inflateInit2(&stream, 15);

    if (err != Z_OK && err != Z_STREAM_END)
    {
        return 1;
    }
    //--------------------------------------



    //----------------------------------------------------
    int flush;
    size_t cntr = 0;
    //----------------------------------------------------


    do
    {
        if (cntr != size__compressed_data)
        {

            //----------------------------------------------
            memcpy(&in_buff_string[0], char_p__to_compressed_data + cntr, CHUNK_SIZE);  

            stream.avail_in = CHUNK_SIZE;
            stream.next_in = (Bytef*)&in_buff_string[0];

            cntr++;
            //----------------------------------------------
           
            flush = Z_NO_FLUSH;
        }
        else
        {
            flush = Z_FINISH;
        }



        do
        {

            stream.avail_out = CHUNK_SIZE;
            stream.next_out = (Bytef*)&out_buff_string[0];


            //------------------------------------------------
            err = inflate(&stream, flush);

            if (err == Z_BUF_ERROR)
            {
                std::cout << "Z_BUF_ERROR" << std::endl;
                return 1;
            }
            //------------------------------------------------

            int nbytes = CHUNK_SIZE - stream.avail_out;

            if (nbytes != 0)
            {
                std::cout << out_buff_string << std::endl;
            }



        } while (stream.avail_out == 0);


    } while (flush != Z_FINISH);


    inflateEnd(&stream);

    return 0;

}

原因分析

  • 错误的Z_BUF_ERROR处理逻辑:Z_BUF_ERROR不是致命错误,它仅表示当前输入或输出缓冲区无法满足解压需求——要么需要更多输入数据,要么需要更大的输出空间。原代码直接在收到该错误时退出,中断了解压流程。
  • 1字节输入的局限性:Zlib的deflate算法需要累积一定量的压缩数据才能解码出输出,单次仅喂入1字节输入时,可能无法立即生成输出,此时inflate返回Z_BUF_ERROR提示需要更多输入,而非操作失败。
  • 循环逻辑漏洞:内层循环仅在输出缓冲区被填满时继续,当输入不足无法产生输出时,内层循环跳出,但外层循环没有处理这种需要继续补充输入的情况,直接进入下一轮,导致流程异常。

解决办法

  1. 修正Z_BUF_ERROR的判断逻辑:仅当inflate返回Z_BUF_ERROR,且已无剩余输入数据(stream.avail_in == 0)且处于Z_FINISH阶段时,才判定为真正的错误。否则应继续补充输入或重试解压。
  2. 调整循环结构:确保在inflate返回Z_BUF_ERROR但还有未处理的输入数据时,继续向流中喂入下一块输入,而非直接退出。
  3. 正确处理Z_FINISH阶段:只有所有输入数据都已喂入后,才使用Z_FINISH标记,此时若仍出现Z_BUF_ERROR,则说明压缩数据损坏或解压逻辑有误。

修改后的代码

#include <iostream>
#include <string>
#include <zlib.h>


static std::string in_buff_string;
static std::string out_buff_string;
static z_stream stream;



int my_uncompress_func__from_memory(unsigned long CHUNK_SIZE, char* char_p__to_compressed_data, unsigned long size__compressed_data)
{
    CHUNK_SIZE = 1;  // 强制1字节分块
    in_buff_string.resize(CHUNK_SIZE);           
    out_buff_string.resize(CHUNK_SIZE);         
    int err;

    stream = { 0 };
    err = inflateInit2(&stream, 15);
    if (err != Z_OK)
    {
        return 1;
    }

    size_t cntr = 0;
    int flush = Z_NO_FLUSH;

    do
    {
        // 仅当当前输入缓冲区为空时,补充新的输入数据
        if (stream.avail_in == 0 && cntr < size__compressed_data)
        {
            memcpy(&in_buff_string[0], char_p__to_compressed_data + cntr, CHUNK_SIZE);  
            stream.avail_in = CHUNK_SIZE;
            stream.next_in = (Bytef*)&in_buff_string[0];
            cntr++;
        }
        // 所有输入都已喂入,切换到FINISH模式
        else if (cntr >= size__compressed_data)
        {
            flush = Z_FINISH;
        }

        stream.avail_out = CHUNK_SIZE;
        stream.next_out = (Bytef*)&out_buff_string[0];

        // 执行解压
        err = inflate(&stream, flush);

        // 处理错误:仅当FINISH阶段且无输入时的Z_BUF_ERROR才是真错误
        if (err == Z_BUF_ERROR)
        {
            if (flush == Z_FINISH && stream.avail_in == 0)
            {
                std::cout << "Fatal Z_BUF_ERROR: corrupted data or invalid stream" << std::endl;
                inflateEnd(&stream);
                return 1;
            }
            // 非致命情况,继续循环补充输入或重试
            continue;
        }
        // 处理其他致命错误
        if (err != Z_OK && err != Z_STREAM_END)
        {
            std::cout << "Inflate error: " << err << std::endl;
            inflateEnd(&stream);
            return 1;
        }

        // 输出解压得到的数据
        int nbytes = CHUNK_SIZE - stream.avail_out;
        if (nbytes != 0)
        {
            std::cout.write(out_buff_string.data(), nbytes);
            std::cout << std::endl;
        }

    } while (!(err == Z_STREAM_END && flush == Z_FINISH));

    inflateEnd(&stream);
    return 0;
}

内容的提问来源于stack exchange,提问作者Serg_

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 18:55:31