• zlib解压缩gzip


    zlib是个著名的开源解压缩库,gzip是一种压缩文件格式。

    zlib可以压缩原始数据并输出gzip文件,gzip文件中除了压缩数据外,还有描述这些数据的文件头,所以当原始数据较小时,会出现zlib的压缩输出会比原始数据还大的情况。

    zlib能使用一个gzip数据头,zlib数据头或者不使用数据头压缩数据。
     
    通常情况下,数据压缩使用zlib数据头,因为这提供错误数据检测。当数据不使用数据头写入时,结果是没有任何错误检测的原始DEFLATE数据,那么解压缩软件的调用者不知道压缩数据在什么地方结束。
    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
    Length:%ld
    ", strSrc, srcLen); 
        /* 压缩 */ 
        ::gzFile file = ::gzopen("d:/1.gz", "wb"); 
        if (file != NULL) 
        { 
            printf("GZip file Writing ...
    "); 
            ::gzwrite(file, strSrc, srcLen); 
            printf("done.
    "); 
        } 
        ::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解压。

  • 相关阅读:
    R语言nest_join()函数
    R语言行/列合并
    ffmpeg 命令将视频转化为图帧
    Natas Wargame Level20 Writeup(会话状态注入/篡改)
    vim简明教程--半小时从入门到精通
    笔记:Spring Cloud Hystrix 异常处理、缓存和请求合并
    【Ecstore2.0】导出问题解决(未导出或导出文件为0字节)
    Android Handler消息处理顺序分析
    着色器语言之变量类型
    Redis源码分析(十一)--- memtest内存检测
  • 原文地址:https://www.cnblogs.com/guoxiaoqian/p/4315195.html
Copyright © 2020-2023  润新知