zlib是個著名的開源解壓縮庫,gzip是一種壓縮文件格式。
zlib可以壓縮原始數據並輸出gzip文件,gzip文件中除了壓縮數據外,還有描述這些數據的文件頭,所以當原始數據較小時,會出現zlib的壓縮輸出會比原始數據還大的情況。
zlib能使用一個gzip數據頭,zlib數據頭或者不使用數據頭壓縮數據。
gzip數據頭比zlib數據頭要大,因為它保存了文件名和其他文件系統信息,事實上這是廣泛使用的gzip文件的數據頭格式。注意zlib函式庫本身不能創建一個gzip文件,但是它相當輕松的通過把壓縮數據寫入到一個有gzip
文件頭的文件中。
zlib提供的工具接口:compress()和decompress()是壓縮內存數據流,並不帶gzip文件頭和尾。java的解壓縮用的是類似的一套東西:
java.util.zip.GZIPInputStream,請注意java的這一套是用來解壓完整的gzip文件格式的,因此如果c語言用zlib的compress()壓縮數據后傳給java,java端是解壓縮不了的,會提示格式錯誤。
zlib創建gzip文件很簡單,跟C語言讀寫文件很相似:
/* 原始數據 */ unsigned char strSrc[] = "hello world! aaaaa 中文測試 哈哈哈~!@#$%^&*()_+yes"; unsigned long srcLen = sizeof(strSrc); printf("Src string:%s\nLength:%ld\n", strSrc, srcLen); /* 壓縮 */ ::gzFile file = ::gzopen("d:/1.gz", "wb"); if (file != NULL) { printf("GZip file Writing ...\n"); ::gzwrite(file, strSrc, srcLen); printf("done.\n"); } ::gzclose(file);
如果想在內存中輸出gzip格式的數據流,而不是寫文件,則用以下方法:
/* Compress gzip data */ /* data 原數據 ndata 原數據長度 zdata 壓縮后數據 nzdata 壓縮后長度 */ int gzcompress(Bytef *data, uLong ndata, Bytef *zdata, uLong *nzdata) { z_stream c_stream; int err = 0; if (data && ndata > 0) { c_stream.zalloc = NULL; c_stream.zfree = NULL; c_stream.opaque = NULL; //只有設置為MAX_WBITS + 16才能在在壓縮文本中帶header和trailer if (deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1; c_stream.next_in = data; c_stream.avail_in = ndata; c_stream.next_out = zdata; c_stream.avail_out = *nzdata; while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata) { if (deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1; } if (c_stream.avail_in != 0) return c_stream.avail_in; for (;;) { if ((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break; if (err != Z_OK) return -1; } if (deflateEnd(&c_stream) != Z_OK) return -1; *nzdata = c_stream.total_out; return 0; } return -1; } /* Uncompress gzip data */ /* zdata 數據 nzdata 原數據長度 data 解壓后數據 ndata 解壓后長度 */ int gzdecompress(Byte *zdata, uLong nzdata, Byte *data, uLong *ndata) { int err = 0; z_stream d_stream = { 0 }; /* decompression stream */ static char dummy_head[2] = { 0x8 + 0x7 * 0x10, (((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF, }; d_stream.zalloc = NULL; d_stream.zfree = NULL; d_stream.opaque = NULL; d_stream.next_in = zdata; d_stream.avail_in = 0; d_stream.next_out = data; //只有設置為MAX_WBITS + 16才能在解壓帶header和trailer的文本 if (inflateInit2(&d_stream, MAX_WBITS + 16) != Z_OK) return -1; //if(inflateInit2(&d_stream, 47) != Z_OK) return -1; while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) { d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ if ((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break; if (err != Z_OK) { if (err == Z_DATA_ERROR) { d_stream.next_in = (Bytef*)dummy_head; d_stream.avail_in = sizeof(dummy_head); if ((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK) { return -1; } } else return -1; } } if (inflateEnd(&d_stream) != Z_OK) return -1; *ndata = d_stream.total_out; return 0; }
以上這兩種方法的輸出都可以被java.util.zip.GZIPInputStream解壓。