一.ZLib与GZip解压缩
ZLib库默认解压缩方法,并非GZip解压缩,而是ZLib的。
zlib(RFC1950):一种格式,是对deflate进行了简单的封装;
gzip(RFC1952):一种格式,也是对deflate进行的封装.
gzip与GZip是一种数据压缩格式,可以大体分为头部,数据部和尾部三个部分
gzip数据头比zlib数据头要大,因为它保存了文件名和其他文件系统信息,事实上这是广泛使用的gzip文件的数据头格式。
而zlib和gzip格式的区别仅仅是头部和尾部不一样,而实际的内容都是deflate编码的,即: gzip = gzip头(10字节) + deflate编码的实际内容 + gzip尾(8字节)
ZLib头部
ZLib头部0x78,0x9c 是zlib数据头(非固定,参考RFC 1951)。或者0x0,0x0,0xFF,0xFF也可以实现正常解压缩,而00 00 FF FF是zlib容错方式的数据块头
GZip头部
第一个字节0x1f(31),第二个字节为0x8b(139),标识为GZIP格式。第三个字节为0x08(8),指示DEFLATE方法.目前只有一种,CM=8;
GZip尾部
GZip尾部:CRC32:4字节。原始(未压缩)数据的32位校验和。
CRC32:4字节。原始(未压缩)数据的32位校验和。
ISIZE:4字节。原始(未压缩)数据的长度的低32位。
GZIP中字节排列顺序是LSB方式,即Little-Endian,与ZLIB中的相反
二.objective-c版本的ZLib与GZip解压缩
ZLib压缩
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
|
+ (NSData *)zlibCompressData:(NSData *)sourceData {
NSUInteger sourceDataLength = [sourceData length];
if (sourceDataLength == 0) {
return sourceData;
}
z_stream stream;
memset(&stream, 0, sizeof(z_stream));
stream.next_in = (Bytef *)[sourceData bytes];
stream.avail_in = (uInt)sourceDataLength;
stream.total_out = 0;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
if (deflateInit(&stream, Z_DEFAULT_COMPRESSION) != Z_OK) {
return nil;
}
const int KBufLen = 1024;
Byte buf[KBufLen];
memset(buf, 0, KBufLen * sizeof(Byte));
BOOL isCompressOK = NO;
NSMutableData *compressedData =
[NSMutableData dataWithLength:sourceDataLength];
[compressedData setData:nil]; //必须得加
int res = 0;
while (stream.avail_out == 0) {
memset(buf, 0, KBufLen * sizeof(Byte));
stream.avail_out = KBufLen;
stream.next_out = buf;
res = deflate(&stream, Z_FINISH);
;
switch (res) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
case Z_BUF_ERROR: {
isCompressOK = NO;
break;
}
default: {
if (res == Z_OK || res == Z_STREAM_END) {
const int dataLen = KBufLen - stream.avail_out;
isCompressOK = YES;
if (dataLen > 0) {
[compressedData appendBytes:buf length:dataLen];
}
}
break;
}
}
if (!isCompressOK) {
break;
}
}
res = deflateEnd(&stream);
if (res != Z_OK) {
return nil;
}
if (isCompressOK) {
return compressedData;
} else {
return nil;
}
}
|
ZLib解压
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
|
+ (NSData *)zlibUncompressData:(NSData *)sourceData {
NSUInteger sourceDataLength = [sourceData length];
if (sourceDataLength == 0) {
return sourceData;
}
z_stream stream;
memset(&stream, 0, sizeof(z_stream));
stream.next_in = (Bytef *)[sourceData bytes];
stream.avail_in = (uInt)sourceDataLength;
stream.total_out = 0;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
int res = inflateInit(&stream);
// inflateInit2(&strm, (15+32))
if (res != Z_OK) {
return nil;
}
const int KBufLen = 1024;
Byte buf[KBufLen];
memset(buf, 0, KBufLen * sizeof(Byte));
BOOL isUncompressOK = NO;
NSMutableData *decompressed = [NSMutableData dataWithLength:sourceDataLength];
[decompressed setData:nil]; //必须得加
while (stream.avail_out == 0) {
memset(buf, 0, KBufLen * sizeof(Byte));
stream.avail_out = KBufLen;
stream.next_out = buf;
res = inflate(&stream, Z_NO_FLUSH);
switch (res) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
case Z_BUF_ERROR: {
isUncompressOK = NO;
break;
}
default: {
if (res == Z_OK || res == Z_STREAM_END) {
const int dataLen = KBufLen - stream.avail_out;
isUncompressOK = YES;
if (dataLen > 0) {
[decompressed appendBytes:buf length:dataLen];
}
}
break;
}
}
if (!isUncompressOK) {
break;
}
}
if (inflateEnd(&stream) != Z_OK) {
return nil;
}
if (isUncompressOK) {
return decompressed;
} else {
return nil;
}
}
|
GZip压缩
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
|
+ (NSData *)gzipCompress:(NSData *)sourceData {
NSUInteger sourceDataLength = [sourceData length];
if (sourceDataLength == 0) {
return sourceData;
}
z_stream stream;
memset(&stream, 0, sizeof(z_stream));
stream.next_in = (Bytef *)[sourceData bytes];
stream.avail_in = (uInt)sourceDataLength;
stream.total_out = 0;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
//只有设置为MAX_WBITS + 16才能在在压缩文本中带header和trailer
if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16,
8, Z_DEFAULT_STRATEGY) != Z_OK) {
return nil;
}
const int KBufLen = 1024;
Byte buf[KBufLen];
memset(buf, 0, KBufLen * sizeof(Byte));
BOOL isCompressOK = NO;
NSMutableData *compressedData =
[NSMutableData dataWithLength:sourceDataLength];
[compressedData setData:nil]; //必须得加
int res = 0;
while (stream.avail_out == 0) {
memset(buf, 0, KBufLen * sizeof(Byte));
stream.avail_out = KBufLen;
stream.next_out = buf;
res = deflate(&stream, Z_FINISH);
;
switch (res) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
case Z_BUF_ERROR: {
isCompressOK = NO;
break;
}
default: {
if (res == Z_OK || res == Z_STREAM_END) {
const int dataLen = KBufLen - stream.avail_out;
isCompressOK = YES;
if (dataLen > 0) {
[compressedData appendBytes:buf length:dataLen];
}
}
break;
}
}
if (!isCompressOK) {
break;
}
}
res = deflateEnd(&stream);
if (res != Z_OK) {
return nil;
}
if (isCompressOK) {
return compressedData;
} else {
return nil;
}
}
|
GZip解压
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
|
+ (NSData *)gzipUncompress:(NSData *)sourceData {
NSUInteger sourceDataLength = [sourceData length];
if (sourceDataLength == 0) {
return sourceData;
}
z_stream stream;
memset(&stream, 0, sizeof(z_stream));
stream.next_in = (Bytef *)[sourceData bytes];
stream.avail_in = (uInt)sourceDataLength;
stream.total_out = 0;
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
int res = inflateInit2(&stream, MAX_WBITS + 16);
// inflateInit2(&strm, (15+32))
//只有设置为MAX_WBITS + 16才能在解压带header和trailer的文本
if (res != Z_OK) {
return nil;
}
const int KBufLen = 1024;
Byte buf[KBufLen];
memset(buf, 0, KBufLen * sizeof(Byte));
BOOL isUncompressOK = NO;
NSMutableData *decompressed = [NSMutableData dataWithLength:sourceDataLength];
[decompressed setData:nil]; //必须得加
while (stream.avail_out == 0) {
memset(buf, 0, KBufLen * sizeof(Byte));
stream.avail_out = KBufLen;
stream.next_out = buf;
res = inflate(&stream, Z_SYNC_FLUSH);
switch (res) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
case Z_STREAM_ERROR:
case Z_BUF_ERROR: {
isUncompressOK = NO;
break;
}
default: {
if (res == Z_OK || res == Z_STREAM_END) {
const int dataLen = KBufLen - stream.avail_out;
isUncompressOK = YES;
if (dataLen > 0) {
[decompressed appendBytes:buf length:dataLen];
}
}
break;
}
}
if (!isUncompressOK) {
break;
}
}
if (inflateEnd(&stream) != Z_OK) {
return nil;
}
if (isUncompressOK) {
return decompressed;
} else {
return nil;
}
}
|
三.示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
NSString* hello = @"helloabc123";
NSData *helloData = [NSData dataWithBytes:hello.UTF8String length:[hello lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSData *compressData = [CommonFuctions zlibCompressData:helloData];
NSData *unCompressData = [CommonFuctions zlibUncompressData:compressData];
NSString* string = [[NSString alloc] initWithData:unCompressData encoding:NSUTF8StringEncoding];
NSLog(@"Zlib compressData Length = %lu compressData = %@", (unsigned long)compressData.length,[compressData description]);
NSData *compressDataGZip = [CommonFuctions gzipCompress:helloData];
NSData *uncompressDataGZip = [CommonFuctions gzipUncompress:compressDataGZip];
NSString* stringRes = [[NSString alloc] initWithData:uncompressDataGZip encoding:NSUTF8StringEncoding];;
NSLog(@"GZip compressData Length = %lu compressData = %@", (unsigned long)compressDataGZip.length,[compressDataGZip description]);
|
四.日志
1
2
3
|
2014-12-02 21:14:20.946 ZlibGZipTest[14417:4245959] Zlib compressData Length = 19 compressData = <789ccb48 cdc9c94f 4c4a3634 32060019 9003d1>
2014-12-02 21:14:24.142 ZlibGZipTest[14417:4245959] GZip compressData Length = 31 compressData = <1f8b0800 00000000 0003cb48 cdc9c94f 4c4a3634 32060012 e873880b 000000>
(lldb)
|
五.结论
1.zlib默认压缩后比gzip小一点。
2.zlib与gzip头尾对比。
- zlib头:789ccb48 zlib尾:32060019 9003d1
- gzip头:1f8b0800 00000000 0003cb48 gzip尾:32060012 e873880b 000000
两者相比差12个字节。
文章作者
梵梵爸
上次更新
2014-12-02
许可协议
原创文章,如需转载请注明文章作者和出处。谢谢