1.字符集与编码

字符集:表示多个字符的集合,如符号,序号、数字,其它等等。

字符编码:把字符编码为指定集合中的某一对象,变成一种特定的字节或字节序列,在计算机中便于存储,传输。

通常字符集都采用对应的编码方式,如ASCII、IOS-8859-1、GB2312、GBK,即表示了字符集又表示了对应的字符编码,但是Unicode例外,它采用的现代模型。

各种字符集编码(聊聊字符集编码与数据压缩)(1)

2.字符集编码的发展

字符集编码的发展,从单字节,发展到双字节,最终到多字节。

(1)单字节

ASCII,用 7 位二进制表示(00000000-01111111 即 0x00-0x7F)。EASCII(Extended ASCII),256 个字符,用 8 位二进制表示(00000000-11111111 即 0x00-0xFF)。

(2)双字节

当计算机传到了亚洲,256 个码位就不够用了。于是乎继续扩大二维表,单字节改双字节,16 位二进制数,65536 个码位。在不同国家和地区又出现了很多编码,大陆的 GB2312、港台的 BIG5、日本的 Shift JIS 等等。

双字节编码是可以变长,主要是为了兼容ASCII码和节省存储容量,但是可能会损失一部分码位。

UNICODE 字符集国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。有多个编码方式,分别是 UTF-8,UTF-16,UTF-32 编码。

(3)多字节

UTF表示Unicode Transformation Format的缩写,是一种Unicode转换格式,后面的数字表示至少用多少个比特位来存储字符。

UTF-8表示一种变长编码方案,使用1-6个字节来存储;

UTF-16使用2个或4个字节来存储,长度固定又可变。

UTF-32表示一种固定长度编码方案,使用4个字节来存储。

Utf8前缀编码格式如下:

各种字符集编码(聊聊字符集编码与数据压缩)(2)

当Unicode 编号范围在 0~FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。当Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储。实际就把较高的一些比特位用D800~DBFF 之间的双字节存储,较低的比特位用DC00~DFFF之间的双字节存储。

各种字符集编码(聊聊字符集编码与数据压缩)(3)

UTF-32 是固定长度的编码,始终占用 4 个字节,足以容纳所有的 Unicode 字符,所以直接存储 Unicode 编号即可,不需要任何编码转换。浪费了空间,提高了效率。

UTF大小端问题

BOM实际就是使用大端(BE)还是小端(LE)问题。

UTF-16BE,大端:就是把高位字节放在低地址表示。

UTF-16LE,小端:就是把低字节放在低地址表示。

UTF在文件的存储。UTF格式在文件中总有固定文件头。UTF-8缺省不带BOM。

当打开一个文件时,怎么识别使用的是UTF-8还是UTF-16.在文件的开头就是标志。

EF BB BF 表示 UTF-8

FE FF 表示 UTF-16BE

FF FE 表示 UTF-16LE

00 00 FE FF 表示 UTF32-BE

FF FE 00 00 表示 UTF32-LE

注意:只有UTF-8兼容ASCII,UTF-32和UTF-16都不兼容ASCII,因为这连个没有单字节编码。

iconv

iconv命令用来转换文件的编码,如将UTF8编码转换成GB18030的编码,Linux下的iconv开发库包括iconv_open,iconv_close,iconv等C函数,实现快速转换。

格式:

iconv -f encoding [-t encoding] [inputfile] ....

选项:

-f encoding :字符从encoding编码开始转换

-t encoding :字符转换到encoding编码

-l:已知的编码字符集合

-o file :指定输出文件

-c :忽略输出的非法字符

-s :禁止警告信息,但不是错误信息

--verbose :显示进度信息

查看支持的格式: iconv -l

UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, UTF-32LE, UTF8, UTF16, UTF16BE, UTF16LE, UTF32, UTF32BE, UTF32LE GB2312 ,GBK ISO-8859-1。

转换各种格式:

各种字符集编码(聊聊字符集编码与数据压缩)(4)

字符集转换编程:

#include <iconv.h>

函数:iconv_t iconv_open (const char* tocode, const char* fromcode);

范例:iconv_t cd = iconv_open(“UTF−8”, “UTF−16”);

函数:int iconv_close (iconv_t cd);

范例:iconv_close(cd);

函数:size_t iconv (iconv_t cd, const char* * inbuf, size_t * inbytesleft, char* * outbuf,

size_t * outbytesleft);

返回值:返回-1 则说明出现异常,错误码

E2BIG:outbuf 没有足够的空间

EILSEQ:遇到无效的多字节序列

EINVAL:遇到不完整的多字节序列

字符集在线工具集合

GBK 内码查询:

http://www.mytju.com/classcode/tools/encode_gb2312.a

完整的 Unicode 字符集:

https://unicode-table.com/c

Unicode 和 UTF 编码转换:

https://www.qqxiuzi.cn/bianma/Unicode-UTF.p

汉字字符集编码查询:

https://www.qqxiuzi.cn/bianma/zifuji.p

3.压缩原理

压缩原理就是找到重复出现的字符串,然后用更短的符号代替,从而达到缩短字符串的目的。本质上,所谓就是找出文件内容的概率分布,将出现概率高的部分代替为更短的形式。内容越重复的文件,可以压缩的越小。如,"ABABABABABABAB"可以压缩成"7AB"。反之内容毫无重复,就很难压缩,极端情况就是,均匀分布的随机字符串,往往一个字符都无法压缩,如任意排列的10个阿拉伯数组(123456789),就无法压缩,再如π,也很难。

香农极限

∑ log2(1/pn) / n = log2(1/p1)/n log2(1/p2)/n ... log2(1/pn)/n;

(1)如果两个文件都包含了1024个符号,在ASCII 码情况下,长度是相等,A文件(只包含abc)的内容50%是 a,30%b,20%是 c,则平均每个符号要占用1.49个二进制位。

0.5*log2(1/0.5) 0.3*log2(1/0.3) 0.2*log2(1/0.2) = 1.49

(2)假如B文件的每个字节出现的概率是0-255,均匀分布的出现概率是1/256,则 pn = 1/256,计算出极限为 8。

Log21/(1/256) = Log2256 = 8

4.Deflate 压缩算法

deflate是一种压缩数据流的算法,任何需要流式压缩的地方都可以,deflate是zip压缩文件的默认算法,除了zip文件,还有7z,xz等其他压缩文件,也是用。

deflate 算法下的压缩器有三种压缩模型:

(1)不压缩数据,对于已经压缩的数据,不再压缩,这样的数据会稍微增加,但会小于其它应用的一种压缩算法。

(2)先用L7zz,再用huffman 编码。压缩的树是Deflate规范定义,所以不需要额外的空间来存储这个树。

(3)先用LZ77,然后再用huffman 编码。压缩树由压缩器生成,并与数据一起存储。

如果数据被分割成不同块,必须使用单一的压缩模式,如果要在这三种压缩模式中相互切换,必须先结束当前块,重新开始一个新的块。

5.LZ77 算法原理

采用字典的方式进行压缩,是一个简单高效的数据压缩算法。把数据中的一些可以组织成短语的字符加入字典,然后再有相同字符出现采用毕节来代替字典中的短语,如此通过标记代替多数重复出现的方式以进行压缩。需先了解 3 个关键词:短语字典,滑动窗口和向前缓冲区。

(1)前向缓冲区

每次读取数据的时候,先把一部分数据预载入前向缓冲区。为移入滑动窗口做准备

(2)一旦数据通过缓冲区,那么它将移动到滑动窗口中,并变成字典的一部分。滑动窗口需要预设一个定值。

(3) 比如字符(A,B,D) ,可以组合的短语为{(A),(A,B),(A,B,D),(B),(B,D),(D)},如果这些字符在滑动窗口里面,可以标记为当前的短语字典,滑动窗口不断向前滑动,短语字典也不断变化。

注意:先通过前向缓冲区预读数据,然后再向滑动窗口移入(滑动窗口有一定长度),在这个过程中,不断寻找与字典中短语匹配的最长短语,最终通过标记符标记,以ABD为例子。这里滑动窗口 和前向缓冲区可以匹配的最长短语是(A,B),然后向前移动的时候再次遇到(A,B)的时候采用标记符代替。

各种字符集编码(聊聊字符集编码与数据压缩)(5)

当压缩数据的时候,前向缓冲区与移动窗口之间在做短语匹配的是后会存在 2 种情况:

(1)找不到匹配时:将未匹配的符号编码成符号标记(多数都是字符本身)

(2)找到匹配时:将其最长的匹配编码成短语标记。

短语标记包含三部分信息:

(1)滑动窗口中的偏移量(从匹配开始的地方计算);

(2)匹配中的符号个数;

(3)匹配结束后的前向缓冲区中的第一个符号。

一旦把 n 个符号编码并生成相应的标记,就将这 n 个符号从滑动窗口的一端移出,并用前向缓冲区中同样数量的符号来代替它们,如此,滑动窗口中始终有最新的短语。

(1)开始

各种字符集编码(聊聊字符集编码与数据压缩)(6)

(2) 滑动窗口中没有数据,所以没有匹配到短语,将字符 A 标记为 A

各种字符集编码(聊聊字符集编码与数据压缩)(7)

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

B

各种字符集编码(聊聊字符集编码与数据压缩)(8)

(4)缓冲区字符(ABCB)在滑动窗口的位移 6 位置找到 AB,成功匹配到短语 AB,将AB 编码为(6,2,C),之所以是 6,是因为窗口的 A 在滑动窗口的索引[6]位置。

各种字符集编码(聊聊字符集编码与数据压缩)(9)

(5)缓冲区字符(BABA)在滑动窗口位移 4 的位置匹配到短语 BAB,将 BAB 编码为

(4,3,A)。

各种字符集编码(聊聊字符集编码与数据压缩)(10)

(6) 缓冲区字符(BCAD)在滑动窗口位移 2 的位置匹配到短语 BC,将 BC 编码为

(2,2,A)

各种字符集编码(聊聊字符集编码与数据压缩)(11)

(7) 缓冲区字符 D,在滑动窗口中没有找到匹配短语,标记为 D

各种字符集编码(聊聊字符集编码与数据压缩)(12)

(8)缓冲区中没有数据进入了,结束

各种字符集编码(聊聊字符集编码与数据压缩)(13)

6.LZ77解压

解压就是压缩的逆向过程,当解码字符标记:将标记编码成字符拷贝到滑动窗口中,解码短语标记:在滑动窗口中查找相应变量,同时找到指定长短的短语进行替换。

(1)开始

各种字符集编码(聊聊字符集编码与数据压缩)(14)

(2)符号标记 A 解码

各种字符集编码(聊聊字符集编码与数据压缩)(15)

(3)符号标记 B 解码

各种字符集编码(聊聊字符集编码与数据压缩)(16)

(4)短语标记(6,2,C)解码。根据 3 中的索引[6]开始,得到 AB,就是重复 AB 再加入上 C,就成了 ABABC,并且滑动窗口滑到最右边的位置。

各种字符集编码(聊聊字符集编码与数据压缩)(17)

(5)短语标记(4,3,A)解码

根据4中的进行标记。

各种字符集编码(聊聊字符集编码与数据压缩)(18)

(6)短语标记(2,2,A)解码

根据5中进行标记。

各种字符集编码(聊聊字符集编码与数据压缩)(19)

(7) 符号标记 D 解码

各种字符集编码(聊聊字符集编码与数据压缩)(20)

LZ77 压缩算法优点:

压缩比相当高。也和你选择滑动窗口大小,以及前向缓冲区大小,以及数据熵有关系。

解压很快,每个标记都明确告知在哪个位置可以读取。

缺点:

压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配。

6.Huffman 算法原理

哈夫曼设计了一个贪心算法来构造最优前缀码,被称为哈夫曼编码(Huffman code),其正确性证明依赖于贪心选择性质和最优子结构。哈夫曼编码可以很有效的压缩数据,具体压缩率依赖于数据本身的特性。

先介绍几个概念:码字、码字长度、定长编码与变长编码。

码字:每个字符可以用一个唯一的二进制串表示,这个二进制串称为这个字符的码字。

码字长度:这个二进制串的长度称为码字长度。码字长度不变就是固定编码,否则就是变长编码。变长编码可以达到比定长编码好得多的压缩率。其核心思想就是赋予高频字符(出现频率高的字符)短(码字长度较短)码字,赋予低频字符长码字。

如果一个文档中,每个字符出现的频率基本一样,那变长编码的优势在压缩方面的优势就不存在了。

哈弗曼会自底向上构造出一棵对应最优编码的二叉树,下面举例来说明。某个文件中有如下字符及其概率。

字符 a b c d e f

概率 45 13 12 16 9 5

构造过程如下图所示:

每个字符都已

经按照出现频率大小排好顺序,在后续的步骤中,每次都将频率最低的两棵树合并,然后用合并后的结果再次排序。注意,排序不是目的,目的是找到这时出现频率最低的两项,以便下次合并,gzip 源码中并没有专门去“排序”,而是使用专门的数据结构把频率最低的两项找到即可。

在叶子节点用矩形表示,每个叶子节点包含一个字符及其频率。中间节点用圆圈表示,包含其孩子节点的频率之和。中间节点指向左孩子的边标记为 0,指向右孩子的边标记为 1。第6步骤的每个字符的编码都是前缀码。

(1) 按照频率大小先排序

各种字符集编码(聊聊字符集编码与数据压缩)(21)

(2)把f和e拿出来组成一个子树,并相加,再把子树相加的结果,再次进行排序

各种字符集编码(聊聊字符集编码与数据压缩)(22)

(3)在重复前面的排序和最小的两个概率相加操作

各种字符集编码(聊聊字符集编码与数据压缩)(23)

(4)依次重复之前的操作

各种字符集编码(聊聊字符集编码与数据压缩)(24)

(5)依次重复之前的操作

各种字符集编码(聊聊字符集编码与数据压缩)(25)

(6)依次重复之前的操作

各种字符集编码(聊聊字符集编码与数据压缩)(26)

代码思想:

利用库中的优先级队列实现哈夫曼树,最后基于哈夫曼树最终实现文件压缩。

(1)统计文件中字符出现的次数,利用优先级队列构建 Haffman 树,生成 Huffman 编码。构造过程中可以使用priority_queue 辅助,每次 pq.top()都可以取出权值(频数)最小的节点。每取出两个最小权值的节点,就 new 出一个新的节点,左右孩子分别指向它们。然后把这个新节点 push 进优先队列。

(2)压缩,实际就是存入压缩编码。利用 Haffman 编码对文件进行压缩,即在压缩文件中按顺序存入每个字符的 Haffman 编码。

各种字符集编码(聊聊字符集编码与数据压缩)(27)

(3)将文件中出现的字符以及它们出现的次数写入配置文件中,以便后续压缩使用。

(4)解压缩:利用配置文件重构 Haffman 树,对文件进行减压缩

后面的文章会来详细分析代码:

7.deflate 采用的改进版 LZ77 算法

三个字节以上的重复串才进行编码,否则不进行编码:

为什么最小匹配3个字节?

gzip 中,<匹配长度,到匹配串开头的距离>对中,"匹配长度"的范围为 3-258,也就是 256 种可能值,需要 8bit来保存。"到匹配串开头的距离"的范围为 0-32K,需要 15bit 来保存。所以一个<匹配长度,到匹配串开头的距离>对需要 23 位,差一位 3 个字节。如果匹配串小于 3 个字节的话,使用<匹配长度,到匹配串开头的距离>对进行替换,不但没有压缩,反而还会增大。所以保存<匹配长度,到匹配串开头的距离>对所需要的位数,决定了最小匹配长度至少要为 3 个字节。

deflate 无损压缩解压算法

先 LZ77 压缩,再用huaffman编码。

deflate 中的 huffman 编码:

对 LZ77 得到的压缩后结果,需要统计字符生成编码表 huffmantree(指示每个编码代表什么字符),根据码表对内容进行编码,具体的压缩大小在于精细分配结构体的位域来实现 Huffman 编码的压缩效果的。编码表huffmantree和编码后的data都一起放置在文件中。

deflate 中的解压:

读取二进制文件,构建huffmantree 表,读取数据根据huffmantree 生成字符。LZ77 解码需要对窗口生成哈希表(数组 链表),对解压的数据,进行搜索匹配拷贝替换为相应的串即可。

8.gzip 格式分析

GZIP 本身只是一种文件格式,其内部通常采用 DEFLATE 数据格式,而 DEFLATE 采用 LZ77 压缩算法来压缩数据。GZIP 文件由 1 到多个“块”组成,实际上通常只有 1 块。每个块包含头、数据和尾三部分。块的概貌如下:

gzip = gzip 头 deflate 编码的实际内容 gzip 尾

zlib = zlib 头 deflate 编码的实际内容 zlib 尾

各种字符集编码(聊聊字符集编码与数据压缩)(28)

(1)头部分

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 字节。更改时间。

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 - 未知

额外的头字段:

(若 FLG.FEXTRA = 1)

(2)数据部分

DEFLATE 数据格式,包含了一系列子数据块。结构如下:

各种字符集编码(聊聊字符集编码与数据压缩)(29)

BFINAL:1 比特。0 - 还有后续子块;1 - 该子块是最后一块。BTYPE:2 比特。00 -- 不压缩,01--静态Huffman编码压缩。10--动态Huffman 编码压缩。11--保留。

(3)尾部分

CRC32:4 字节。原始数据的32位校验和。ISIZE:4 字节。原始数据长度的低32位。

GZIP 中字节排列顺序是 LSB 方式,即 Little-Endian,与 ZLIB 中的相反。

9.zlib 库 API 分析

(1)下载源码包

下载 http://www.zlib.net/,选择 zlib-1.2.11.tar.gz

(2)下载

wget http://www.zlib.net/zlib-1.2.11.tar.gz

(3)解压

tar -zxvf zlib-1.2.11.tar.gz

(3)进入目录

cd zlib-1.2.11

(4)配置

./configure

(5)编译

make

(6)检查,要全部为 yes

make check

(4)安装

sudo make install

基础数据结构:

各种字符集编码(聊聊字符集编码与数据压缩)(30)

各种字符集编码(聊聊字符集编码与数据压缩)(31)

各种字符集编码(聊聊字符集编码与数据压缩)(32)

压缩函数:

deflateInit :参数比较少,里面实际就是调用deflateInit2

deflateInit2:

deflate : 压缩函数。

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

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

compress2 : 带 level 的压缩方式。

deflateInit2 : 初始化函数

各种字符集编码(聊聊字符集编码与数据压缩)(33)

功能:压缩初始化内部流状态,zalloc,zfree和opaque字段必须在调用之前初始化,若zalloc 和 zfree 被初始化为 Z_NULL,deflateInit会更新它们而使用默认的分配函数。

压缩级别为Z_DEFAULT_COMPRESSION,使用0到9之间的数,1表示最快速度的压缩,9表示最优压缩,0表示不做任何压缩,Z_DEFAULT_COMPRESSION是速度和最优压缩的折衷。

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

#define Z_NO_COMPRESSION 0 //不压缩

#define Z_BEST_SPEED 1 //速度优先,可以理解为最低限度的压缩.

#define Z_BEST_COMPRESSION 9 //压缩优先,但是速度会有些慢

#define Z_DEFAULT_COMPRESSION (-1) //默认选项,compress 里面用的就是这个选

返回值:

成功返回Z_OK,没有足够的内存则返回 Z_MEM_ERROR,若压缩级别无效,返回Z_STREAM_ERROR,版本不兼容则返回 Z_VERSION_ERROR。如果没有错误信息则 msg 被设置为 0。

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 的长度.

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 //用于普通数据

Z_FILTERED,用于由 filter(或者称为 predictor)生成的数据.过滤的数据包含很多小的随机数据。这种情况下,压缩算法能够获得更好的压缩效果。该选项可以强制更多的哈夫 曼 编 码 和 更 少 的 字 符 匹 配 。 有 时 候 可 以 作 为 Z_DEFAULT_STRATEGY 和

Z_HUFFMAN_ONLY 的折衷。

Z_FIXED,阻止使用动态哈夫曼编码,从而允许获得更简单的解码。

strategy 参数只影响压缩比,而不会影响到压缩输出的正确性,因此没有正确的设置也不要紧

deflate函数尽可能压缩数据,当输入缓存为空或输出缓冲满了就会停止,带来输出延迟,除非强行刷新缓冲区。

各种字符集编码(聊聊字符集编码与数据压缩)(34)

deflate 会执行下面的一个或者两个动作都执行,avail_in或avail_out 被设置,使用提供更多输入数据和消耗更多输出数据的方式,

(1)从 next_in 开始压缩输入数据,进而更新next_in 和 avail_in。如果不是所有输入数据可以被处理(缓冲没有足够的空间),next_in和avail_in会更新,当再次调用deflate()函数时输入数据会从这一点开始被处理。从而更新avail_in 或 avail_out;avail_out 在函数调用之前千万不能为 0。应用程序可以随时消耗被压缩的输出数据。如输出缓存满或每次调用deflate()之后,若deflate返回Z_OK并avail_out 为 0 时,deflate()必须再次被调用(说明输出缓存区还有数据应该被读取)

(2)next_out 开始提供更多输出数据从而更新 next_out 和 avail_out,如果 flush参数不是为 0 的化这个动作是强制性的,经常性的强制刷新缓存会降低压缩比率,只有必要的时候去设置这个参数。

Int flush 的参数:

Z_NO_FLUSH:允许压缩算法累计产生多少数据再输出,以达到压缩率最高。

Z_SYNC_FLUSH:将所有等待输出的数据刷新到输出缓冲区,以字节为边界进行对齐。这个可能会降低压缩算法的效率,只用于必要的时候。

Z_FINISH:输入和待输出的数据都被处理完,则返回 Z_STREAM_END。如果返回 Z_OK or Z_BUF_ERROR 则需要再次调用 Z_FINISH 直到返回 Z_STREAM_END。

deflateEnd:资源释放

压缩完成后,释放空间,仅仅释放deflateInit 中申请的空间,自己申请的空间还是要自己释放。

各种字符集编码(聊聊字符集编码与数据压缩)(35)

解压函数

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

inflateInit2 :解压初始化的基础函数

infalte :解压函数

inflateEnd :同deflateEnd作用类似

uncompress :解压缩

解压初始化:

各种字符集编码(聊聊字符集编码与数据压缩)(36)

strm:和deflate 一样,初始化三个回调。

windownBits :含义和deflateInit2 一样

解压函数:

各种字符集编码(聊聊字符集编码与数据压缩)(37)

z_streamp : 四个参数

strm.next_in = 待解压数据

strm.next_out = 解压以后数据存储的 buffer

strm.avail_in = 待解压数据的长度

strm.avail_out = 解压数据存储 buffer 的长度

flush :如果是 Z_NO_FLUSH,说明还有数据没有解压。

如果是Z_FINISH说明这是最后一包待解压的数据

资源释放:

各种字符集编码(聊聊字符集编码与数据压缩)(38)

10.gzip 压缩提升网站速度

讲讲对于Nginx而言,怎样去优化。

# 开启 gzip gzip on # 启用 gzip 压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-9,数字越大压缩的越好,也越占用 CPU 时间,后面会有详细说明 gzip_comp_level 1; # 进行压缩的文件类型。javascript 有多种形式。其中的值可以在 mime.types 文件中找到。 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/vnd.ms-fontobject font/ttf font/opentype font/x-woff image/svg xml; # 是否在 http header 中添加 Vary: Accept-Encoding,建议开启 gzip_vary on; # 禁用 IE 6 gzip gzip_disable "MSIE [1-6]\."; #设置压缩所需要的缓冲区大小 gzip_buffers 32 4k; # 设置 gzip 压缩针对的 HTTP 协议版本,没做负载的可以不用 # gzip_http_version 1.0; # 开启缓存 location ~* ^. \.(ico|gif|jpg|jpeg|png)$ { access_log off; expires 2d; } location ~* ^. \.(css|js|txt|xml|swf|wav)$ { access_log off; expires 24h; } location ~* ^. \.(html|htm)$ { expires 1h; } location ~* ^. \.(eot|ttf|otf|woff|svg)$ { access_log off; expires max; } # 格式 # expires 30s; # expires 30m; # expires 2h; # expires 30d;

以上单独参数的说明:

gzip on:

打开或关闭gzip

Syntax: gzip on | off;

Default: gzip off;

Context: http, server, location, if in location

gzip_buffers:

用于处理请求压缩的缓冲区数量和大小。如32 4K表示按照内存页为单位,建议使用默认值。

Syntax: gzip_buffers number size;

Default: gzip_buffers 32 4k|16 8k;

Context: http, server, location

gzip_comp_level

设置gzip压缩级别,级别越低压缩速度越快,文件压缩比越小。反之速度越慢文件压缩比越大。

Syntax: gzip_comp_level level;

Default: gzip_comp_level 1;

Context: http, server, location

gzip_disable

通过表达式,表明哪些 UA 头部使用 gzip 压缩。

Syntax: gzip_disable regex ...;

Default: —

Context: http, server, location

This directive appeared in version 0.6.23.

gzip_min_length

表示当资源大于该长度时,才进行压缩,资源大小取响应头中的Content-Length 进行比较,如果响应头不存在 Content_length 信息,该限制参数对于这个响应包是不起作用的;这个值不建议设置太小,如果太小,一些本来很小的文件,经过压缩,反而变大,建议1k起,当然也需要根据自己实际的情况来去设计。

Syntax: gzip_min_length length;

Default: gzip_min_length 20;

Context: http, server, location

gzip_http_version

识别 http 协议的版本,早期的浏览器不支持 gzip 压缩,用户会看到乱码。默认在http1.0的协议下不开启gzip压缩。

Syntax: gzip_http_version 1.0 | 1.1;

Default: gzip_http_version 1.1;

Context: http, server, location

gzip_proxied

Nginx 作为反向代理的时候启用:

off – 关闭所有的代理结果数据压缩

expired – 如果 header 中包含 "Expires" 头信息,启用压缩

no-cache – 如果 header 中包含 "Cache-Control:no-cache" 头信息,启用压缩

no-store – 如果 header 中包含 "Cache-Control:no-store" 头信息,启用压缩

private – 如果 header 中包含 "Cache-Control:private" 头信息,启用压缩

no_last_modified – 启用压缩,如果 header 中包含 "Last_Modified" 头信息,

启用压缩

no_etag – 启用压缩,如果 header 中包含 "ETag" 头信息,启用压缩

auth – 启用压缩,如果 header 中包含 "Authorization" 头信息,启用压缩

any – 无条件压缩所有结果数据

Syntax: gzip_proxied off | expired | no-cache | no-store | private | no_last_modified

| no_etag | auth | any ...;

Default: gzip_proxied off;

Context: http, server, location

gzip_types

设置需要压缩的 MIME 类型,如果不在设置类型范围内的请求不进行压缩。根据这个值进行匹配。"text/html"类型总是会被压缩。

Syntax: gzip_types mime-type ...;

Default: gzip_types text/html;

Context: http, server, location

gzip_vary

在响应头添加

AcceptEncoding:gzip,对于本身不支持agip压缩的客户端浏览器有用。

Syntax: gzip_vary on | off;

Default: gzip_vary off;

Context: http, server, location

本篇文章就分析到这里,欢迎点赞,收藏,分享。

,