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
原文地址:http://bhlzlx.blog.51cto.com/3389283/1590010