zlib實現解壓的例子官方已經給出
html
http://www.zlib.net/zlib_how.html ide
最多見的解壓方式就是現成從堆分配出適合大小的內存,直接向這個內存裏解壓,這樣是不錯的,一些狀況下這樣是很是適合的,可是若是文件很大,須要實現一個流式解壓的功能,好比文件很是大,須要向文件系統裏寫文件。this
實現的效果以下:.net
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讀取實現一個流式讀取接口htm
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這個改爲代理模式應該會更好,其實如今就是那麼個代理模式的意思。get