首页 > 代码库 > zlib流式解压

zlib流式解压

zlib实现解压的例子官方已经给出

http://www.zlib.net/zlib_how.html

最常见的解压方式就是现成从堆分配出适合大小的内存,直接向这个内存里解压,这样是不错的,一些情况下这样是非常适合的,但是如果文件很大,需要实现一个流式解压的功能,比如文件非常大,需要向文件系统里写文件。

实现的效果如下:

    FILE * file = fopen("text.txt","wb+");
    InflateStream inflateStream("dest.file");
    char buffer[1024];
    while(!inflateStream.Eof())
    {
        int bytes = inflateStream.Inflate(buffer,1024);
        fwrite(buffer,1,bytes,file);
    }
    fclose(file);

为了方便扩展,定义一个解压前的数据流式读取接口

struct IIStream
{
    virtual size_t GetLength() = 0;
    virtual size_t Read(size_t size_,unsigned char * buff_out_) = 0;
    virtual bool   Eof() = 0;
    virtual bool   Valid() = 0;
    virtual void    Release() = 0;
};

针对FILE读取实现一个流式读取接口

struct StdFileStream:public IIStream
{
    FILE * m_file;
    unsigned long m_iLen;
    StdFileStream(const char * szPath)
    {
        m_file = fopen(szPath,"rb+");
        if(m_file)
        {
            m_iLen = ftell(m_file);
            fseek(m_file,0,SEEK_END);
            m_iLen = ftell(m_file) - m_iLen;
            fseek(m_file,0,SEEK_SET);
        }
        else
        {
            m_iLen = 0;
        }
    }

    bool Valid()
    {
        return m_iLen > 0;
    }
    size_t GetLength()
    {
        return m_iLen;
    }
    size_t Read(size_t size_,unsigned char * buff_out_)
    {
        return fread(buff_out_,1,size_,m_file);
    }

    bool Eof()
    {
        return feof(m_file);
    }

    void Release()
    {
        if(m_file)
            fclose(m_file);
        delete this;
    }
};

IIStream * CreateStdFileStream(const char * szPath )
{
    return new StdFileStream(szPath);
}

为方便扩展利用内存池再提供一个内存管理接口

void * AllocateMem(size_t size_)
{
    return malloc(size_);
}

void RecycleMem(void * p)
{
    free(p);
}

解压流的实现

struct InflateStream
{
    z_stream        m_stream;
    IIStream*       m_origStream;
    int             m_last_inflate_;
    unsigned char *      m_indeflateBuff;
    unsigned char *      m_origBuff;
    InflateStream(const void * _stream_in)
    {
        m_origStream = CreateStdFileStream((const char *)_stream_in);
        m_indeflateBuff = (unsigned char *)AllocateMem(CHUNK_SIZE);
        m_origBuff = (unsigned char *)AllocateMem(CHUNK_SIZE);
        // 初始化z_stream结构体
        memset(&m_stream,0,sizeof(m_stream));
        inflateInit(&m_stream);

        m_last_inflate_ = Z_OK;
    }
    ~InflateStream()
    {
        m_origStream->Release();
        RecycleMem(m_indeflateBuff);
        RecycleMem(m_origBuff);
    }

    size_t Inflate__(unsigned char * _buff_out,size_t _block_size)
    {
        m_stream.next_out = _buff_out;
        m_stream.avail_out = _block_size;
        m_last_inflate_ = inflate(&m_stream,Z_NO_FLUSH);
        /*
        #define Z_OK            0
        #define Z_STREAM_END    1
        #define Z_NEED_DICT     2
        #define Z_ERRNO        (-1)
        #define Z_STREAM_ERROR (-2)
        #define Z_DATA_ERROR   (-3)
        #define Z_MEM_ERROR    (-4)
        #define Z_BUF_ERROR    (-5)
        #define Z_VERSION_ERROR (-6)
        */
        if(m_last_inflate_ > Z_STREAM_END)
        {
            return 0;
        }
        return _block_size - m_stream.avail_out;
    }
    size_t Inflate(char * buff_out,size_t size_)
    {
        int inflate_bytes = 0;
        static int i = 0;
        do
        {
            int orig_bytes = 0;
            if(!m_stream.avail_in)
            {
                orig_bytes = m_origStream->Read(CHUNK_SIZE,m_origBuff);
                m_stream.avail_in = CHUNK_SIZE;
                m_stream.next_in = m_origBuff;
            }
            do
            {
                i++;
                int bytes_read = 0;
                memset(m_indeflateBuff,0,CHUNK_SIZE);
                bytes_read = Inflate__(m_indeflateBuff,size_ - inflate_bytes);
                assert(bytes_read);
                memcpy(buff_out+inflate_bytes,m_indeflateBuff,bytes_read);
                inflate_bytes += bytes_read;
                if(inflate_bytes >=size_)
                {
                    return size_;
                }
                else
                {
                    return inflate_bytes;
                }
            }while(m_stream.avail_in);
        }while(m_last_inflate_ != Z_STREAM_END);
    }

    bool Eof()
    {
        if(this->m_last_inflate_ == Z_STREAM_END)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
};

大概就是这么一回事,IIStream*       m_origStream;其实有那么点像原始流delegate这个改成代理模式应该会更好,其实现在就是那么个代理模式的意思。

本文出自 “冰狐浪子的博客” 博客,请务必保留此出处http://bhlzlx.blog.51cto.com/3389283/1590010

zlib流式解压