HTTP请求头Accept-Encoding会通知(给服务器)客户端可以理解的内容编码方式——通常是某种压缩算法。通过内容协商,服务器会选择客户端提出的一种方法,使用它并在响应头Content-Encoding中通知客户端选择。今天我们就来看看最常见的gzip压缩方法Gzip使用的压缩原理用于压缩的deflate算法。具体地,首先对待压缩文件使用LZ77算法的变体进行压缩,然后将得到的结果使用哈夫曼编码方法进行压缩。先介绍一下LZ77算法。如果文件中有两块相同的内容,我们只要知道前一块的位置和大小,就可以确定下一块的内容。所以我们可以利用两者之间的距离和内容的长度来替换后一段的内容,文件就这样被压缩了。重复内容越多,压缩率越高。压缩时,从文件的开头到文件的结尾,逐字节向后处理。使用从当前处理的字节开始的字符串去匹配滑动窗口中的每一个字符串,找到最长的匹配字符串。如果当前处理字节开头的字符串在窗口中有匹配的字符串,则先输出一个标志位,表示后面是匹配对,输出匹配对,然后是该字符串之后的下一个字节刚处理完的需要加急处理。如果以当前处理的字节开头的字符串在窗口中没有匹配的字符串,则先输出一个标志位表示后面是未修改的字节,然后不加修改的输出当前处理的字节,然后继续处理当前处理的字节byte的下一个字节。解压时,从文件开头到文件结尾,每次读取一个flag,根据这个flag判断后面的匹配对。如果是组队,则单独与固定数量的对,然后将匹配的字符串输出到当前位置。如果是一个没有变化的字节,就输出这个字节。解压缩比压缩花费更少的时间。哈夫曼编码使用哈夫曼树来生成编码。要执行哈夫曼编码,必须首先读取整个文件。在读取过程中,统计每个符号出现的次数(我们把字节的256个值看作256个符号)。然后根据符号出现的次数建立哈夫曼树,通过哈夫曼树得到每个符号的新编码。对于文件中出现频率较高的符号,其霍夫曼编码的位数较少。对于在文件中出现频率较低的符号,其霍夫曼码的位数较多。然后用新的编码替换文件中的每个字节。构建哈夫曼树:将所有符号视为一个节点,节点的值就是它出现的次数。进一步将这些节点视为只有一个节点的树。每次从所有的树中找出值最小的两棵树,为两棵树创建一个父节点,然后用两棵树和它们的父节点组成一棵新树,而这棵新树的值是的总和它的两个子树的值。这种情况一直持续到最后所有的树都变成一棵树。我们得到了一棵霍夫曼树。通过哈夫曼树得到哈夫曼编码:这棵哈夫曼树是一棵二叉树,它的所有叶子节点都是符号,它的中间节点在哈夫曼树的生成过程中不断建立。我们在哈夫曼树的所有父节点到它的左子节点的路径上标记0,在从右子节点的路径上标记1。现在我们从根节点开始,到所有叶子节点的路径都是一个0和1的序列。我们用从根节点到一个叶子节点的路径上的0和1的序列作为叶子节点的哈夫曼编码。总结:压缩:读取文件,统计每个符号出现的次数。根据每个符号出现的次数,建立哈夫曼树,得到每个符号的哈夫曼码。在压缩文件中保存每个符号出现次数的信息,将文件中的每个符号替换为其哈夫曼码,并输出。解压缩:获取有关存储在压缩文件中的每个符号的出现次数的信息。根据每个符号出现的次数,建立哈夫曼树,得到每个符号的哈夫曼码。将压缩文件中的每一个哈夫曼编码替换为对应的符号,并输出。
