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这个改成代理模式应该会更好,其实现在就是那么个代理模式的意思。
转载于:https://blog.51cto.com/bhlzlx/1590010