zlib实现解压的例子官方已经给出
http://www.zlib.net/zlib_how.html
最常见的解压方式就是现成从堆分配出适合大小的内存,直接向这个内存里解压,这样是不错的,一些情况下这样是非常适合的,但是如果文件很大,需要实现一个流式解压的功能,比如文件非常大,需要向文件系统里写文件。
实现的效果如下:
1
2
3
4
5
6
7
8
9
|
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); |
为了方便扩展,定义一个解压前的数据流式读取接口
1
2
3
4
5
6
7
8
|
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读取实现一个流式读取接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
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); } |
为方便扩展利用内存池再提供一个内存管理接口
1
2
3
4
5
6
7
8
9
|
void * AllocateMem( size_t size_) { return malloc (size_); } void RecycleMem( void * p) { free (p); } |
解压流的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
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 free task manager.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 if(m_last_inflate_ == Z_STREAM_END) { 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这个改成代理模式应该会更好,其实现在就是那么个代理模式的意思。