精华内容
下载资源
问答
  • 下面小编就为大家带来一篇JAVA中的deflate压缩实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 本文实例讲述了C#实现页面GZip或Deflate压缩的方法。分享给大家供大家参考。具体分析如下: .NET Framework里 System.IO.Compression下有两个可用于页面压缩的类,GZipStream和 DeflateStream. 在页面被传输之前,...
  • zlib-Deflate压缩算法

    千次阅读 2019-05-31 18:26:48
    最近在做一些关于网络优化的一些事情,涉及到对纯数据(Data、字符串、Json等)进行压缩,用到了Deflate压缩算法,这里就简单说一下如何用OC实现 Deflate 先看代码 (后面会给出详细解析) Deflate.h // // ...

    写在前边

    最近在做一些关于网络优化的一些事情,涉及到对纯数据(Data、字符串、Json等)进行压缩,用到了Deflate压缩算法,这里就简单说一下如何用OC实现 Deflate

    先看代码 (后面会给出详细解析)

    Deflate.h

    //
    //  Deflate.h
    //  CompressionTest
    
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface Deflate : NSObject
    
    + (NSData *)compress: (NSData *)data;
    + (NSData *)decompress: (NSData *)data;
    @end
    
    NS_ASSUME_NONNULL_END
    
    

    Deflate.m

    //
    //  Deflate.m
    //  CompressionTest
    
    #import "Deflate.h"
    
    #include <zlib.h>
    
    #define CHUNK 16384
    
    @implementation Deflate
    
    /**
     Deflate 压缩
     @param data 需要压缩的数据
     @return 返回压缩数据
     */
    + (NSData *)compress:(NSData *)data {
        
        if ([data length] == 0) return data;
        // 初始化 z_stream
        z_stream stream;
        stream.zalloc = Z_NULL;
        stream.zfree = Z_NULL;
        stream.opaque = Z_NULL;
        stream.total_out = 0;
        stream.next_in = (Bytef *)[data bytes];
        stream.avail_in = (int)[data length];
        
        // Compresssion Levels:
        //   Z_NO_COMPRESSION
        //   Z_BEST_SPEED
        //   Z_BEST_COMPRESSION
        //   Z_DEFAULT_COMPRESSION
        
        if (deflateInit2(&stream,
                         Z_DEFAULT_COMPRESSION,
                         Z_DEFLATED,
                         -15,
                         MAX_MEM_LEVEL,
                         Z_DEFAULT_STRATEGY) != Z_OK) return nil;
        NSMutableData * compressed = [NSMutableData dataWithLength: CHUNK];
        do {
            if (stream.total_out >= [compressed length])
                // 追加长度
                [compressed increaseLengthBy:CHUNK];
            stream.next_out = [compressed mutableBytes] + stream.total_out;
            stream.avail_out = (uint)[compressed length] - (uint)stream.total_out;
            deflate(&stream, Z_FINISH);
            
        } while (stream.avail_out == 0);
        deflateEnd(&stream);
        [compressed setLength: stream.total_out];
        return [NSData dataWithData:compressed];
    }
    
    
    /**
     Deflate 解压缩
    
     @param data 需要解压数据
     @return 已经解压的数据
     */
    + (NSData *)decompress:(NSData *)data {
        
        if ([data length] == 0) return data;
        // 初始化 z_stream
        z_stream strm;
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        strm.total_out = 0;
        strm.next_in = (Bytef *)[data bytes];
        strm.avail_in = (int)[data length];
    
        unsigned full_length = (int)[data length];
        unsigned half_length = (int)[data length] / 2;
        NSMutableData * decompressed = [[NSMutableData alloc]
                                        initWithLength: full_length + half_length];
        BOOL done = false;
        int status;
        
        if (inflateInit2(&strm, -15) != Z_OK) return nil;
        while (!done) {
            if (strm.total_out >= [decompressed length])
                [decompressed increaseLengthBy: half_length];
            strm.next_out = [decompressed mutableBytes] + strm.total_out;
            strm.avail_out = (uint)[decompressed length] - (uint)strm.total_out;
            
            status = inflate(&strm, Z_SYNC_FLUSH);
            if (status == Z_STREAM_END)
                done = YES;
            else if (status != Z_OK)
                break;
        }
        if (inflateEnd(&strm) != Z_OK) return nil;
        if (done) {
            [decompressed setLength: strm.total_out];
            return [NSData dataWithData:decompressed];
        }
        return nil;
    }
    
    @end
    
    

    相关概念

    deflate(RFC1951):一种压缩算法,使用LZ77和哈弗曼进行编码;
    zlib(RFC1950):一种格式,是对deflate进行了简单的封装,他也是一个实现库(delphi中有zlib,zlibex)
    gzip(RFC1952):一种格式,也是对deflate进行的封装。

    gzip = gzip头 + deflate编码的实际内容 + gzip
    zlib = zlib头 + deflate编码的实际内容 + zlib

    基础数据结构

    z_stream : 压缩算法,压缩程度以及输入输出buffer和长度等都保存在这里,可以理解为压缩上下文。

    常用的函数

    deflateInit : 参数比较少,里面的实现其实是调用的deflateInit2

    deflateInit2: 压缩初始化的基础函数,有很多参数,下面会重点介绍。

    deflate : 压缩函数。

    deflateEnd : 压缩完成以后,释放空间,但是注意,仅仅是释放deflateInit中申请的空间,自己申请的空间还是需要自己释放。

    inflateInit : 解压初始化函数,内部调用的inflateInit2

    inflateInit2 : 解压初始化的基础函数,后面重点介绍。

    infalte : 解压函数。

    inflateEnd : 同deflateEnd作用类似。

    compress : 全部附加选项默认压缩,内部调用compress2。

    compress2 : 带level的压缩方式。

    uncompress : 解压缩。

    压缩函数介绍

    deflateInit2 : 初始化函数

    函数原型为 :

    int ZEXPORT deflateInit2(z_streamp strm, int level, int method, int windowBits, int memLevel, intstrategy)
    

    z_stream:这个是压缩上下文,我们依照官方给的例子进行初始化

    strm.zalloc = NULL; 
    strm.zfree = NULL; 
    strm.opaque = NULL;
    
    strm.next_in = 你的待压缩数据
    strm.next_out = 压缩以后数据存储的buffer
    strm.avail_in = 待压缩数据的长度
    strm.avail_out = 压缩数据存储buffer的长度.
    

    level: 压缩的等级,目前有四个值

    #define Z_NO_COMPRESSION         0 	//不压缩
    #define Z_BEST_SPEED             1	//速度优先,可以理解为最低限度的压缩.
    #define Z_BEST_COMPRESSION       9	//压缩优先,但是速度会有些慢
    #define Z_DEFAULT_COMPRESSION  (-1) //默认选项,compress里面用的就是这个选项
    /* compression levels */
    

    method: 值只有一个,当前唯一的defalte压缩方法,用于以后扩展

    #define Z_DEFLATED   8
    /* The deflate compression method (the only one supported in this version) */
    

    windowBits: 窗口比特数

    * 	-(15 ~ 8) : 纯deflate压缩
    * 	+(15 ~ 8) : 带zlib头和尾
    * 	> 16 : 带gzip头和尾
    

    memLevel: 目前只有一个选项,MAX_MEM_LEVEL,无非是运行过程中对内存使用的限制.

    /* Maximum value for memLevel in deflateInit2 */
    #ifndef MAX_MEM_LEVEL
    #  ifdef MAXSEG_64K
    #    define MAX_MEM_LEVEL 8
    #  else
    #    define MAX_MEM_LEVEL 9
    #  endif
    #endif
    

    strategy :用于调整压缩算法,直接给默认就行Z_DEFAULT_STRATEGY.

    #define Z_FILTERED            1	//用于由filter(或者称为predictor)生成的数据
    #define Z_HUFFMAN_ONLY        2	//用于强制哈夫曼编码(不做字符匹配)
    #define Z_RLE                 3	//限制匹配长度为1
    #define Z_FIXED               4	//阻止使用动态哈夫曼编码,从而允许获得更简单的解码
    #define Z_DEFAULT_STRATEGY    0	//用于普通数据
    /* compression strategy; see deflateInit2() below for details */
    
    

    Z_FILTERED,用于由filter(或者称为predictor)生成的数据.过滤的数据包含很多小的随机数据。这种情况下,压缩算法能够获得更好的压缩效果。该选项可以强制更多的哈夫曼编码和更少的字符匹配。有时候可以作为Z_DEFAULT_STRATEGY和Z_HUFFMAN_ONLY的折衷。
    Z_FIXED,阻止使用动态哈夫曼编码,从而允许获得更简单的解码。
    strategy参数只影响压缩比,而不会影响到压缩输出的正确性,因此没有正确的设置也不要紧。

    deflate 压缩函数

    函数原型 :

    ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
    

    解压函数介绍

    inflateInit2 初始化

    原型函数

    inflateInit2(z_streampstrm, int windowBits)
    

    strm: 和deflate一样,初始化三个回调以后即可,有的参考文档说还需要初始化第四个选项,具体记不清哪个了,不过我试过以后发现貌似不用。

    windownBits : 含义和deflateInit2一样,而且一定要对应起来.

    inflate 解压

    函数原型

    ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
    

    z_streamp : 四个参数.

    strm.next_in = 你的待解压数据
    strm.next_out = 解压以后数据存储的buffer
    strm.avail_in = 待解压数据的长度
    strm.avail_out = 解压数据存储buffer的长度.
    

    flush : 和deflate一样,如果是Z_NO_FLUSH说明还有数据没有解压,如果是Z_FINISH说明这是最后一包待解压数据.

    inflateEnd: 释放上面两步骤里面申请的资源.

    uncompress :

    函数原型 :

    ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,const Bytef *source, uLong sourceLen));
    
    

    dest : 解压以后的数据存在这里

    destLen : dest 大小

    source : 待解压数据buffer

    sourceLen : 待解压数据长度

    其实这个函数就是简单封装了inflateInit, inflate, inflateEnd.同样,这个函数只适合单独解压场景,不适合需要多次传入的场景.

    相关链接:

    https://yq.aliyun.com/articles/40985
    https://github.com/tsolomko/SWCompression

    展开全文
  • 本篇文章是对使用Deflate算法对文件进行压缩和解压缩的方法进行了详细的分析介绍,需要的朋友参考下
  • ​ gzip是一种数据格式,默认且目前仅使用deflate算法压缩data部分; ​ Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台。当应用Gzip压缩到一个纯文本文件时,效果是非常明显的,大约可以...

    一、什么是gzip

    ​ gzip是一种数据格式,默认且目前仅使用deflate算法压缩data部分;

    ​ Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台。当应用Gzip压缩到一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小。这取决于文件中的内容。

    ​ 利用Apache中的Gzip模块,我们可以使用Gzip压缩算法来对Apache服务器发布的网页内容进行压缩后再传输到客户端浏览器。这样经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。

    ​ 网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是Gzip与搜索引擎的抓取工具有着更好的关系。例如 Google就可以通过直接读取gzip文件来比普通手工抓取更快地检索网页。在Google网站管理员工具(Google Webmaster Tools)中你可以看到,sitemap.xml.gz 是直接作为Sitemap被提交的。

    ​ 而这些好处并不仅仅限于静态内容,PHP动态页面和其他动态生成的内容均可以通过使用Apache压缩模块压缩,加上其他的性能调整机制和相应的服务器端 缓存规则,这可以大大提高网站的性能。因此,对于部署在Linux服务器上的PHP程序,在服务器支持的情况下,我们建议你开启使用Gzip Web压缩。

    PS**:详情参考:http://baike.baidu.com/item/gzip?fr=aladdin**

    二、什么是deflate

    ​ DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。

    ​ 它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在RFC 1951规范中。

    ​ 人们普遍认为DEFLATE不受任何专利所制约,并且在LZW(GIF文件格式使用)相关的专利失效之前,这种格式除了在ZIP文件格式中得到应用之外也在gzip压缩文件以及PNG图像文件中得到了应用。

    ​ DEFLATE压缩与解压的源代码可以在自由、通用的压缩库zlib上找到。

    ​ 更高压缩率的DEFLATE是7-zip所实现的。AdvanceCOMP也使用这种实现,它可以对gzip、PNG、MNG以及ZIP文件进行压缩从而得到比zlib更小的文件大小。在Ken Silverman的KZIP与PNGOUT中使用了一种更加高效同时要求更多用户输入的DEFLATE程序。

    ​ deflate是一种压缩算法,是huffman编码的一种加强。

    ​ deflate与gzip解压的代码几乎相同,可以合成一块代码。

    三、web服务器处理http压缩的过程

    ​ \1. Web服务器接收到浏览器的HTTP请求后,检查浏览器是否支持HTTP压缩(Accept-Encoding 信息);

    ​ \2. 如果浏览器支持HTTP压缩,Web服务器检查请求文件的后缀名;

    ​ \3. 如果请求文件是HTML、CSS等静态文件,Web服务器到压缩缓冲目录中检查是否已经存在请求文件的最新压缩文件;

    ​ \4. 如果请求文件的压缩文件不存在,Web服务器向浏览器返回未压缩的请求文件,并在压缩缓冲目录中存放请求文件的压缩文件;

    ​ \5. 如果请求文件的最新压缩文件已经存在,则直接返回请求文件的压缩文件;

    ​ \6. 如果请求文件是动态文件,Web服务器动态压缩内容并返回浏览器,压缩内容不存放到压缩缓存目录中。

    下面是两个演示图:

    未使用Gzip:
    在这里插入图片描述
    开启使用Gzip后:
    在这里插入图片描述

    四、gzip与deflate区别

    ​ deflate使用inflateInit(),而gzip使用inflateInit2()进行初始化,比 inflateInit()多一个参数: -MAX_WBITS,表示处理raw deflate数据。因为gzip数据中的zlib压缩数据块没有zlib header的两个字节。使用inflateInit2时要求zlib库忽略zlib header。在zlib手册中要求windowBits为8…15,但是实际上其它范围的数据有特殊作用,见zlib.h中的注释,如负数表示raw deflate。

    ​ Apache的deflate变种可能也没有zlib header,需要添加假头后处理。即MS的错误deflate (raw deflate).zlib头第1字节一般是0x78, 第2字节与第一字节合起来的双字节应能被31整除,详见rfc1950。例如Firefox的zlib假头为0x7801,python zlib.compress()结果头部为0x789c。

    ​ deflate 是最基础的算法,gzip 在 deflate 的 raw data 前增加了 10 个字节的 gzheader,尾部添加了 8 个字节的校验字节(可选 crc32 和 adler32) 和长度标识字节。

    ​ 安装它们的Apache Web服务器版本的差异。Apache 1.x系列没有内建网页压缩技术,所以才去用额外的第三方mod_gzip 模块来执行压缩。而Apache 2.x官方在开发的时候,就把网页压缩考虑进去,内建了mod_deflate 这个模块,用以取代mod_gzip。虽然两者都是使用的Gzip压缩算法,它们的运作原理是类似的。

    ​ 压缩质量。mod_deflate 压缩速度略快而mod_gzip 的压缩比略高。一般默认情况下,mod_gzip 会比mod_deflate 多出4%~6%的压缩量。

    ​ 对服务器资源的占用。 一般来说mod_gzip 对服务器CPU的占用要高一些。mod_deflate 是专门为确保服务器的性能而使用的一个压缩模块,mod_deflate 需要较少的资源来压缩文件。这意味着在高流量的服务器,使用mod_deflate 可能会比mod_gzip 加载速度更快。即在服务器性能足够的情况下,使用mod_gzip,虽然会耗费服务器性能,但是值得(压缩更快更好);在服务器性能不足的情况下,使用mod_deflate 确保性能。

    ​ 从Apache 2.0.45开始,mod_deflate 可使用DeflateCompressionLevel 指令来设置压缩级别。该指令的值可为1(压缩速度最快,最低的压缩质量)至9(最慢的压缩速度,压缩率最高)之间的整数,其默认值为6(压缩速度和压缩质 量较为平衡的值)。这个简单的变化更是使得mod_deflate 可以轻松媲美mod_gzip 的压缩。

    五、开启mod_gzip、mod_deflate

    ​ Apache上利用Gzip压缩算法进行压缩的模块有两种:mod_gzip 和mod_deflate。 要使用Gzip Web压缩,请首先确定你的服务器开启了对这两个组件之一的支持。在Linux服务器上,现在已经有越来越多的空间商开放了对它们的支持,有的甚至是同时 支持这两个模块的。例如目前Godaddy、Bluehost及DreamHosts等空间商的服务器都已同时支持mod_gzip 和mod_deflate。

    ​ 通过查看HTTP头,我们可以快速判断使用的客户端浏览器是否支持接受gzip压缩。若发送的HTTP头中出现以下信息,则表明你的浏览器支持接受相应的gzip压缩:

    ​ Accept-Encoding: gzip 支持mod_gzip

    ​ Accept-Encoding: deflate 支持mod_deflate

    ​ Accept-Encoding: gzip,deflate 同时支持mod_gzip 和mod_deflate

    ​ mod_deflate 是apache自带的模块,当然是在apache 2后支持的,以前1的时候是mod_gzip,启用mod_deflate可以很好的为节省网页大小,只不过是占用服务器的资源和内存.用户看到页面的速度会大大加快。在apache2.0以上(包括apache2.0)的版中gzip压缩使用的是mod_deflate模块

    1. 查看apache的安装模式
    apachectl -l

    发现 mod_so.c,ok可以动态加模块,不用重新编译。

    2. 安装mod_deflate
    找到原有的apache安装包安装mod_deflate
    cd httpd-2.0.59/modules/filters
    /usr/local/apache2/bin/apxs -i -c -a mod_deflate.c

    PS:apxs命令参数说明:
    ​ -i 此选项表示需要执行安装操作,以安装一个或多个动态共享对象到服务器的modules目录中。
    ​ -a 此选项自动增加一个LoadModule行到httpd.conf文件中,以激活此模块,或者,如果此行已经存在,则启用之。
    ​ -A 与 -a 选项类似,但是它增加的LoadModule命令有一个井号前缀(#),即此模块已经准备就绪但尚未启用。
    ​ -c 此选项表示需要执行编译操作。它首先会编译C源程序(.c)files为对应的目标代码文件(.o),然后连接这些目标代码和files中其余的目标代码文件(.o和.a),以生成动态共享对象dsofile 。如果没有指定 -o 选项,则此输出文件名由files中的第一个文件名推测得到,也就是默认为mod_name.so 。

    3修改Apache的http.conf文件,去除mod_deflate.so前面的注释

    LoadModule deflate_module modules/mod_deflate.so

    4在根目录中新建.htaccess文件,定制压缩规则

    #GZIP压缩模块配置

    #启用对特定MIME类型内容的压缩

    SetOutputFilter DEFLATESetEnvIfNoCase Request_URI .(?:gif|jpe?g|png|exe|t?gz|zip|bz2|sit|rar|pdf|mov|avi|mp3|mp4|rm)$ no-gzip dont-vary #设置不对压缩的文件AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-httpd-php application/x-javascript #设置对压缩的文件

    5对指定的文件配置缓存的生存时间,去除mod_headers.so模块前面的注释

    LoadModule headers_module modules/mod_headers.so

    6在根目录中新建.htaccess文件,定制压缩规则

    #文件缓存时间配置

    <FilesMatch “.(flv|gif|jpg|jpeg|png|ico|swf|js|css)$”>

    Header set Cache-Control “max-age=2592000”

    里面的文件MIME类型可以根据自己情况添加,至于PDF 、图片、音乐文档之类的这些本身都已经高度压缩格式,重复压缩的作用不大,反而可能会因为增加CPU的处理时间及浏览器的渲染问题而降低性能。所以就没必要再通过Gzip压缩。通过以上设置后再查看返回的HTTP头,出现以下信息则表明返回的数据已经过压缩。即网站程序所配置的Gzip压缩已生效。

    Content-Encoding: gzip

    注:不管使用mod_gzip 还是mod_deflate,此处返回的信息都一样。因为它们都是实现的gzip压缩方式。

    遇到的问题以及解决:

    1:

    apach2 安装mod_deflate后restart,直接

    load /opt/apache/modules/mod_deflate.so into server: /opt/apache/modules/mod_deflate.so: undefined symbol: deflate 异常的痛苦

    什么ldd mod_deflate.so后再export LIB_LIBRARY_PATH呀,都试了N次,google也go了N天

    终于在google上go出来一篇文章,终于解决,方法如下: vi /usr/local/apache2/bin/apr-config 修改LDFLAGS=" " 为 LDFLAGS="-lz" 然后再apxs -ica mod_deflate.c 就OK了.

    2:
    apach2 安装mod_deflate后restart,直接

    module deflate_module is built-in and can’t be loaded …

    这说明该模块已经安装,不必再LoadModule deflate_module启用它。

    只需做

    展开全文
  • 一、压缩原理 压缩原理其实很简单,就是找出那些重复出现的字符串,然后用更短的符号代替, 从而达到缩短字符串的目的。比如,有一篇文章大量使用"中华人民共和国"这个词语, 我们用"中国"代替,就缩短了 5 个字符...

    一、压缩原理

    • 压缩原理其实很简单,就是找出那些重复出现的字符串,然后用更短的符号代替, 从而达到缩短字符串的目的。比如,有一篇文章大量使用"中华人民共和国"这个词语, 我们用"中国"代替,就缩短了 5 个字符,如果用"华"代替,就缩短了6个字符。事实上, 只要保证对应关系,可以用任意字符代替那些重复出现的字符串
    • 本质上,所谓"压缩"就是找出文件内容的概率分布,将那些出现概率高的部分代替成更短的形式。所以:
      • 内容越是重复的文件,就可以压缩地越小。比如,"ABABABABABABAB"可以压缩成"7AB"
      • 相应地,如果内容毫无重复,就很难压缩。极端情况就是,遇到那些均匀分布的随机字符串,往往连一个字符都压缩不了。比如,任意排列的10个阿拉伯数字 (5271839406),就是无法压缩的;再比如,无理数(比如π)也很难压缩

    压缩极限

    • 概念:当每一个字符都不重复的时候,就不能再去压缩了,也就是不能无限的压缩
    • 香农极限:

    • 下面是一个例子。假定有两个文件都包含1024个符号,在ASCII码的情况下,它们的长度是相等的,都是1KB。甲文件的内容 50%是a,30%b,20%是c,文本里面只有abc,则平均每个符号要占用1.49个二进制位

    • 比如每个字节的数值概率是0~255,均匀分布每个数值出现的概率 1/256,如果一 段文字的字节数值是平均分布,则Pn = 1/256,计算出极限为8

    二、Deflate压缩算法

    • deflate压缩算法用来很多地方:
      • 例如其是zip压缩文件的默认算法、在zip文件中,在7z, xz 等其他的压缩文件中都用
      • gzip压缩算法、zlib压缩算法等都是对defalte压缩算法的封装(下面会介绍)
      • gzip、zlib等压缩程序都是无损压缩,因此对于文本的压缩效果比较好,对视频、图片等压缩效果不是很好(视频一般都是采用有损压缩算法),所以对于视频、图片这种已经是二进制形式的文件可以不需要压缩,因为效果也不是很明显
    • 实际上deflate只是一种压缩数据流的算法。 任何需要流式压缩的地方都可以用
    • Deflate压缩算法=LZ77算法+哈夫曼编码
    • deflate算法下的压缩器有三种压缩模型:
      • 不压缩数据,对于已经压缩过的数据,这是一个明智的选择。 这样的数据会会稍稍增加,但是会小于在其上再应用一种压缩算法
      • 压缩,先用LZ77压缩,然后用huffman编码。 在这个模型中压缩的树是Deflate规范规定定义的, 所以不需要额外的空间来存储这个树
      • 压缩,先用LZ77压缩,然后用huffman编码。 压缩树是由压缩器生成的,并与数据 一起存储
    • 数据被分割成不同的块,每个块使用单一的压缩模式。 如过压缩器要在这三种压缩模式中相互切换,必须先结束当前的块,重新开始一个新的块

    信息熵

    • 数据为何是可以压缩的,因为数据都会表现出一定的特性,称为熵。绝大多数的数据所表现出来的容量往往大于其熵所建议的最佳容量。比如所有的数据都会有一定的冗余性,我们可以把冗余的数据采用更少的位对频繁出现的字符进行标记,也可以基于数 据的一些特性基于字典编码,代替重复多余的短语

    三、LZ77算法原理

    • Ziv和Lempel于1977年发表题为“顺序数据压缩的一个通用算法(A Universal Algorithm for Sequential Data Compression )。LZ77 压缩算法采用字典的方式进行压缩, 是一个简单但十分高效的数据压缩算法。其方式就是把数据中一些可以组织成短语(最长字符)的字符加入字典,然后再有相同字符出现采用标记来代替字典中的短语,如此通过标记代替多数重复出现的方式以进行压缩
    • 关键词术语:
      • 前向缓冲区:每次读取数据的时候,先把一部分数据预载入前向缓冲区。为移入滑动窗口做准备,大小可以自己设定
      • 滑动窗口:一旦数据通过缓冲区,那么它将移动到滑动窗口中,并变成字典的一部分。滑动窗口的大小也可以自己设定的
      • 短语字典:从字符序列 S1...Sn,组成n个短语。比如字符(A,B,D),可以组合的短语为 {(A),(A,B),(A,B,D),(B),(B,D),(D)},如果这些字符在滑动窗口里面,就可以记为当前的短语字典,因为滑动窗口不断的向前滑动,所以短语字典也是不断的变化
    • 优缺点:
      • 大多数情况下LZ77压缩算法的压缩比相当高,当然了也和你选择滑动窗口大小, 以及前向缓冲区大小,以及数据熵有关系
      • 缺点:其压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配
      • 优点:不过解压过程会很快,因为每个标记都明确告知在哪个位置可以读取了

    算法的主要逻辑

    • LZ77 的主要算法逻辑就是,先通过前向缓冲区预读数据,然后再向滑动窗口移入(滑动窗口有一定的长度),不断的寻找能与字典中短语匹配的最长短语,然后通过标记符标记
    • 我们还以字符ABD为例子,看如下图:

    • 目前从前向缓冲区中可以和滑动窗口中可以匹配的最长短语就是(A,B),然后向前移动的时候再次遇到(A,B)的时候采用标记符代替

    LZ77压缩原理

    • 当压缩数据的时候,前向缓冲区与滑动窗口之间在做短语匹配的是后会存在2种情况:
      • (1)找不到匹配时:将未匹配的符号编码成符号标记(多数都是字符本身)
      • (2)找到匹配时:将其最长的匹配编码成短语标记
    • 短语标记包含三部分信息:
      • (1)滑动窗口中的偏移量(从匹配开始的地方计算)
      • (2)匹配中的符号个数
      • (3)匹配结束后的前向缓冲区中的第一个符号
    • 一旦把 n 个符号编码并生成相应的标记,就将这 n 个符号从滑动窗口的一端移出, 并用前向缓冲区中同样数量的符号来代替它们,如此,滑动窗口中始终有最新的短语

    演示案例

    • 初始化:如下所示,滑动窗口的初始化大小为8,向前缓冲区的大小为4

    • 压缩A:滑动窗口中没有数据,所以没有匹配到短语,将字符A标记为A

    • 压缩B:滑动窗口中有 A,没有从缓冲区中字符(BABC)中匹配到短语,依然把B标记为B

    • 压缩ABC:缓冲区字符(ABCB)在滑动窗口的位移6位置找到AB,成功匹配到短语AB,将AB编码为(6,2,C)
      • 6:重复的字符串的起始位置。此处为滑动窗口索引[6]处
      • 2:重复的字符串长度为2,也就是AB
      • C:重复的字符串的下一个字符是C

    • 压缩BABA:缓冲区字符(BABA)在滑动窗口位移4的位置匹配到短语 BAB,将 BAB 编码为(4,3,A)
      • 4:重复的字符串的起始位置。此处为滑动窗口索引[4]处
      • 3:重复的字符串长度为3,也就是BAB
      • A:重复的字符串的下一个字符是A

    • 压缩BCA:缓冲区字符(BCAD)在滑动窗口位移 2 的位置匹配到短语BC,将BC编码为 (2,2,A)
      • 2:重复的字符串的起始位置。此处为滑动窗口索引[2]处
      • 2:重复的字符串长度为3,也就是BC
      • A:重复的字符串的下一个字符是A

    • 最后压缩D:缓冲区字符 D,在滑动窗口中没有找到匹配短语,标记为D

    • 缓冲区中没有数据进入了,结束

    LZ77解压原理

    • 解压类似于压缩的逆向过程,通过解码标记和保持滑动窗口中的符号来更新解压数据
    • 当解码字符标记:将标记编码成字符拷贝到滑动窗口中
    • 解码短语标记:在滑动窗口中查找相应偏移量,同时找到指定长短的短语进行替换

    演示案例

    • 以上面最终压缩的样子为例,起始如下所示

    • 解压A:标记为A,直接将A解压

    • 解压B:标记为B,直接将B解压

    • 解压(6,2,C):标记为(6,2,C),通过在滑动窗口中找到索引[6]处,然后找到2个字符(AB),最后加上一个C,所以最终解压出来的就是ABC

    • 解压(4,3,A):标记为(4,3,C),通过在滑动窗口中找到索引[4]处,然后找到3个字符(BAB),最后加上一个A,所以最终解压出来的就是BABA

    • 解压(2,2,A):标记为(2,2,A),通过在滑动窗口中找到索引[2]处,然后找到2个字符(BC),最后加上一个A,所以最终解压出来的就是BCA

    • 解压D:标记为D,直接将D解压

    四、Huffman算法原理

    • 哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码(Huffman code), 其正确性证明依赖于贪心选择性质和最优子结构。哈夫曼编码可以很有效的压缩数据,具体压缩率依赖于数据本身的特性
    • 这里我们先介绍几个概念:
      • 码字:每个字符可以用一个唯一的二进制串表示,这个二进制串称为这个字符的码字
      • 码字长度:这个二进制串的长度称为这个码字的码字长度
      • 定长编码:码字长度固定就是定长编码。
      • 变长编码:码字长度不同则为变长编码。
    • 变长编码可以达到比定长编码好得多的压缩率,其思想是赋予高频字符(出现频率高的字符)短(码字长度较短)码字,赋予低频字符长码字。例如,我们 用 ASCII 字符编辑一个文本文档,不论字符在整个文档中出现的频率,每个字符都要占 用一个字节。如果我们使用变长编码的方式,每个字符因在整个文档中的出现频率不同导致码字长度不同,有的可能占用一个字节,而有的可能只占用一比特,这个时候,整 文档占用空间就会比较小了。当然,如果这个文本文档相当大,导致每个字符的出现频率基本相同,那么此时所谓变长编码在压缩方面的优势就基本不存在了(这点要十分明确,这是为什么压缩要分块的原因之一,源码分析会详细讲解)

    构造过程

    • 哈夫曼编码会自底向上构造出一棵对应最优编码的二叉树,我们使用下面这个例子来说明哈夫曼树的构造过程
    • 首先,我们已知在某个文本中有如下字符及其出现频率:

    • 构造过程如下图所示:
      • 在一开始,每个字符都已经按照出现频率大小排好顺序
      • 在后续的步骤中,每次都将频率最低的两棵树合并,然后用合并后的结果再次排序(注意,排序不是目的,目的是找到这时出现频率最低的两项,以便下次合并。gzip 源码中并没有专门去“排序”,而是使用专门的数据结构把频率最低的两项找到即可)
      • 叶子节点用矩形表示,每个叶子节点包含一个字符及其频率。中间节点用圆圈表示,包含其孩子节点的频率之和。中间节点指向左孩子的边标记为 0, 指向右孩子的边标记为 1。一个字符的码字对应从根到其叶节点的路径上的边的标签序列
      • 图1为初始集合,有六个节点,每个节点对应一个字符;图2到图5为中间步骤, 图6为最终哈夫曼树。此时每个字符的编码都是前缀码

    哈夫曼编码编码实现

    • 利用库中的优先级队列实现哈夫曼树,最后基于哈夫曼树最终实现文件压缩
    • 代码结构为:
      • 1.统计文件中字符出现的次数,利用优先级队列构建Haffman树,生成Huffman编码。构造过程可以使用 priority_queue 辅助,每次pq.top()都可以取出权值(频数)最小 的节点。每取出两个最小权值的节点,就new出一个新的节点,左右孩子分别指向它 们。然后把这个新节点 push 进优先队列。
      • 2.压缩:利用 Haffman 编码对文件进行压缩,即在压缩文件中按顺序存入每个字符 的 Haffman 编码。 码表(实际存储是对应数值的概率,然后调用程序生成码表) + 编码
      • 3.将文件中出现的字符以及它们出现的次数写入配置文件中,以便后续压缩使用
      • 4.解压缩:利用配置文件重构 Haffman 树,对文件进行减压缩
    • 源码链接为:https://github.com/dongyusheng/csdn-code/tree/master/HuffmanDecompression
    • 目录结构为:FileCompress.hpp、HuffmanTree.hpp、main.cpp三个文件是哈夫曼编码的主要代码,testfile/目录下是一些测试的代码(用来压缩和解压缩的)

    代码讲解

    • Compress()函数:会构造一棵哈夫曼树,然后读取文件,将文件中的每个字符进行编码形成一个二进制值,然后打印出来

    • Compress()函数:码表的相关信息,info._ch打印的是每个字符,info._count是这个字符出现的频率,就是上面“构造过程”对应的第一张图。然后会将这个码表的信息写入压缩文件中

    • Compress()函数:压缩完成之后会打印相关信息,其中“huffman code table  size”是码表的大小,就是

    • Uncompress()函数:读取码表(写入字符的信息)

    • Uncompress()函数:然后重构哈夫曼树

    编码测试

    • 先编译程序
    g++ -o huffman main.cpp HuffmanTree.hpp FileCompress.hpp

    • 现在我们想将./testfile/下的test_file1文件进行压缩,输入下面的命令即可,效果如下图所示:
      • 红框圈出来的部分:每一个字符的信息,以红框为例,[105868]代表该字符在文件中的偏移(seek),125代表该字符的ASCII值,01111101代表哈夫曼编码(值越大说明出现的次数越少,值越小说明出现的次数越多)
      • 下面箭头是打印的程序总的运行信息
    ./huffman ./testfile/test_file1

    • 程序运行之后会生成一个压缩文件(.huffman)和一个解压缩文件(.unhuffman)。通过下图可以看出test_file1压缩之后由104K变为了65K,解压之后又回到了104K,压缩比为0.625

    • 现在我们对视频进行压缩看看,因为视频文件大小比较大,所以在进行解压缩的时候大量的打印信息会导致程序运行很久才会结束,因此在对视频进行解压缩之前将FileCompress.hpp文件中的一处打印语句注释掉(如下图所示)

    • 注释掉之后重新编译,运行,然后查看解压缩信息,如下所示,可以看出视频在压缩之后只减少了1M,因此视频的压缩效率比较低
    g++ -o huffman main.cpp HuffmanTree.hpp FileCompress.hpp
    
    ./huffman ./testfile/1.flv

     

    • 现在我们使用Windows自带的.zip压缩工具来对比一下,可以看到其压缩效率比我们上面的哈夫曼解压缩的效率要高

    五、gzip压缩算法

    • gzip压缩算法是对deflate进行的封装。gzip本身只是一种文件格式,其内部通常采用Deflate数据格式,而Deflate采用LZ77压缩算法来压缩数据
    • gzip=gzip头+deflate 编码的实际内容+gzip尾
    • gzip文件由1到多个“块”组成,实际上通常只有1块。每个块包含头、数据和尾3部分。块的概貌如下:

    头部分

    • ID1 与 ID2:各 1 字节。固定值,ID1 = 31 (0x1F),ID2 = 139(0x8B),指示 GZIP 格式
    • CM:1 字节。压缩方法。目前只有一种:CM = 8,指示 DEFLATE 方法
    • FLG:1 字节。标志:
      • bit 0 FTEXT - 指示文本数据
      • bit 1 FHCRC - 指示存在 CRC16 头校验字段
      • bit 2 FEXTRA - 指示存在可选项字段
      • bit 3 FNAME - 指示存在原文件名字段
      • bit 4 FCOMMENT - 指示存在注释字段 bit 5-7 保留
    • MTIME:4 字节。更改时间。UINX 格式
    • XFL:1 字节。附加的标志。当 CM = 8 时, XFL = 2 - 最大压缩但最慢的算法;XFL = 4 - 最快但最小压缩的算法
    • OS:1 字节。操 作系统,确切地说应该是文件系统。有下列定义:
      • 0 - FAT 文件系统 (MS-DOS, OS/2, NT/Win32)
      • 1 - Amiga
      • 2 - VMS/OpenVMS
      • 3 - Unix
      • 4 - VM/CMS
      • 5 - Atari TOS
      • 6 - HPFS 文件系统 (OS/2, NT)
      • 7 - Macintosh
      • 8 - Z-System
      • 9 - CP/M
      • 10 - TOPS-20
      • 11 - NTFS 文件系统 (NT)
      • 12 - QDOS
      • 13 - Acorn RISCOS
      • 255 - 未知

    额外的头字段

    • 存在额外的可选项时,SI1 与 SI2 指示可选项 ID,XLEN 指示可选项字节数。如 SI1 = 0x41 ('A'),SI2 = 0x70 ('P'),表示可选项是 Apollo 文件格式的额外数据
    • (若 FLG.FEXTRA = 1)

    • (若 FLG.FNAME = 1)

    • (若 FLG.FCOMMENT = 1)

    • (若 FLG.FHCRC = 1)

    数据部分

    • BFINAL:1 比特。0 - 还有后续子块;1 - 该子块是最后一块
    • BTYPE:2 比特。00 - 不压缩;01 - 静态 Huffman 编码压缩;10 - 动态 Huffman 编码压缩;11 - 保留
    • 各种情形的处理过程,请参考后面列出的 RFC 文档

    尾部分

    • CRC32:4 字节。原始(未压缩)数据的 32 位校验和
    • ISIZE:4 字节。原始(未压缩)数 据的长度的低 32 位。
    • GZIP 中字节排列顺序是 LSB 方式,即 Little-Endian,与 ZLIB 中的相反

    六、zlib压缩算法

    七、Nginx中的gzip模块

    展开全文
  • 关于gzip/deflate压缩,有放入管道压缩,和非管道压缩方法。 0x02.管道压缩 Node中的I/O是异步的,因此对磁盘和网络的读写需要通过回调函数来读取数据。 当内存中无法一次装下需要处理的数据时,或者一边读取一边...
  • * 功能:将批量文件内容使用DEFLATE压缩算法压缩,Base64编码生成字符串并返回&lt;br&gt; * 适用到的交易:批量代付,批量代收,批量退货&lt;br&gt; * @param filePath 批量文件-全路径文件名...

     1、先把文件以流的方式InputStream读入in.read(s, 0, in.available());

    /**
    	 * 功能:将批量文件内容使用DEFLATE压缩算法压缩,Base64编码生成字符串并返回<br>
    	 * 适用到的交易:批量代付,批量代收,批量退货<br>
    	 * @param filePath 批量文件-全路径文件名<br>
    	 * @return
    	 */
    	public static String enCodeFileContent(String filePath,String encoding){
    		String baseFileContent = "";
    		
    		File file = new File(filePath);
    		if (!file.exists()) {
    			try {
    				file.createNewFile();
    			} catch (IOException e) {
    				logger.error(e.getMessage(), e);
    			}
    		}
    		InputStream in = null;
    		try {
    			in = new FileInputStream(file);
    			int fl = in.available();
    			if (null != in) {
    				byte[] s = new byte[fl];
    				in.read(s, 0, fl);
    				// 压缩编码
                    //TODO
    				baseFileContent = 
    			}
    		} catch (Exception e) {
    			logger.error(e.getMessage(), e);
    		} finally {
    			if (null != in) {
    				try {
    					in.close();
    				} catch (IOException e) {
    					logger.error(e.getMessage(), e);
    				}
    			}
    		}
    		return baseFileContent;
    	}

    2、进行BASE64编码

    Base64.encodeBase64(inputByte);

    3、对byte[]进行压缩 deflater方法

    /**
    	 * 压缩.
    	 * 
    	 * @param inputByte 需要解压缩的byte[]数组
    	 * @return 压缩后的数据
    	 * @throws IOException
    	 */
    	public static byte[] deflater(final byte[] inputByte) throws IOException {
    		int compressedDataLength = 0;
    		Deflater compresser = new Deflater();
    		compresser.setInput(inputByte);
    		compresser.finish();
    		ByteArrayOutputStream o = new ByteArrayOutputStream(inputByte.length);
    		byte[] result = new byte[1024];
    		try {
    			while (!compresser.finished()) {
    				compressedDataLength = compresser.deflate(result);
    				o.write(result, 0, compressedDataLength);
    			}
    		} finally {
    			o.close();
    		}
    		compresser.end();
    		return o.toByteArray();
    	}

     综上:

    baseFileContent = new String(Base64.encodeBase64(Util.deflater(s)),encoding);

     

     

    展开全文
  • deflate = require ( 'permessage-deflate' ) ; var exts = new Extensions ( ) ; exts . add ( deflate ) ; 可以配置扩展名,例如: var Extensions = require ( 'websocket-extensions' ) , deflate = require...
  • DEFLATE 压缩算法

    千次阅读 2014-07-03 16:48:04
     DEFLATE是同时使用了LZ77算法与哈夫曼编码(Huffman Coding)的一个无损数据压缩算法。它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在RFC 1951规范中。  人们普遍认为DEFLA
  • 启用Apache压缩模块mod_deflate: 网站随着用户访问量的增加和内容量的增加,网站的带宽会不断的增加,随之就是网站成本的增加,并且当内容量增大的时候,客户端如果带宽小,就会影响用户的体验,因此从这两方面考虑...
  • Zlib库对网页中deflate压缩数据的解压

    千次阅读 2017-06-13 17:18:19
    Zlib解压deflate算法压缩后的数据
  • 压缩 HTML,然后使用 Gzip 或 Deflate 压缩它 要安装它,请使用以下命令: npm install twee-compressor-extension --save 编辑您的应用程序的package.json : "dependencies": { "twee-compressor-extension...
  • C# Deflate 压缩与解压缩

    千次阅读 2015-07-01 11:36:57
     string httpRequestMessage = string.Format("{{\"status\":\"{0}\",\"message\":\"{1}\",\"userInfo\":{2}}}", "12", "Deflate压缩POST测试!", "[]");  return new ...
  • zip_deflate压缩易语言源码 天哥软件
  • Js算法 zip_deflate(压缩)与zip_inflate(解压),
  • 读取 unicode 数据文件并将其转换为使用 deflate 压缩的 avro 文件的示例 Python 脚本。 此示例中包含的数据来自 Million Song Dataset 项目: : 。 数据受其许可的约束,该许可总结在此处: : 。 使用: 克隆 ...
  • DEFLATE压缩数据格式规范翻译,原版文档及官方代码库实现,可以从zlib官网下载获取。 非专业人员,仅供参考。
  • gzip是一种数据格式,默认且目前仅使用deflate算法压缩data部分; deflate是一种压缩算法,是huffman编码的一种加强。 deflate与gzip解压的代码几乎相同,可以合成一块代码。 区别仅有: deflate使用...
  • 在文件的传输过程中,为了使大文件能够更加方便快速的传输,一般采用压缩的办法来对文件压缩后再传输,JAVA中的java.util.zip包中的Deflater和Inflater类为使用者提供了DEFLATE算法的压缩功能,以下是自已编写的压缩...
  • deflate压缩

    千次阅读 2013-12-07 00:04:38
    deflate(RFC1951):一种压缩算法,使用LZ77和哈弗曼进行编码;  zlib(RFC1950):一种格式,是对deflate进行了简单的封装;  gzip(RFC1952):一种格式,也是对deflate进行的封装。  可以看出deflate是最核心的算法...
  • DEFLATE压缩字符串

    千次阅读 2013-08-05 13:55:13
    //deflate算法 Compress the bytes byte[] requestXMLDeflate = new byte[requestXmlDES.length]; Deflater compresser = new Deflater(Deflater.DEFLATED); compresser.setInput(requestXmlDES); compresse
  • 一个压缩库,可实现许多压缩算法,例如LZ4,Zstd,LZMA,Snappy,Brotli,GZip和Deflate 。 它通过减少用于缓存的内存使用量和网络流量来帮助您提高性能。 Nuget软件包 包裹名字 版本 描述 包含GZip,Deflate和( ...
  • 2 /// Deflate压缩函数 3 /// 4 /// 5 /// 6 public string DeflateCompress(string strSource) 7 { 8 if (strSource == null || strSource.Length > 8 * 1024) 9 throw new System.Argum

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,472
精华内容 12,988
关键字:

deflate压缩