字符集:表示多个字符的集合,如符号,序号、数字,其它等等。
通常字符集都采用对应的编码方式,如ASCII、IOS-8859-1、GB2312、GBK,即表示了字符集又表示了对应的字符编码,但是Unicode例外,它采用的现代模型。
字符集编码的发展,从单字节,发展到双字节,最终到多字节。
ASCII,用 7 位二进制表示(00000000-01111111 即 0x00-0x7F)。EASCII(Extended ASCII),256 个字符,用 8 位二进制表示(00000000-11111111 即 0x00-0xFF)。
当计算机传到了亚洲,256 个码位就不够用了。于是乎继续扩大二维表,单字节改双字节,16 位二进制数,65536 个码位。在不同国家和地区又出现了很多编码,大陆的 GB2312、港台的 BIG5、日本的 Shift JIS 等等。
UNICODE 字符集国际标准字符集,它将世界各种语言的每个字符定义一个唯一的编码,以满足跨语言、跨平台的文本信息转换。有多个编码方式,分别是 UTF-8,UTF-16,UTF-32 编码。
UTF表示Unicode Transformation Format的缩写,是一种Unicode转换格式,后面的数字表示至少用多少个比特位来存储字符。
UTF-16使用2个或4个字节来存储,长度固定又可变。
Utf8前缀编码格式如下:
当Unicode 编号范围在 0~FFFF 之间的字符,UTF-16 使用两个字节存储,并且直接存储 Unicode 编号,不用进行编码转换,这跟 UTF-32 非常类似。当Unicode 编号范围在 10000~10FFFF 之间的字符,UTF-16 使用四个字节存储。实际就把较高的一些比特位用D800~DBFF 之间的双字节存储,较低的比特位用DC00~DFFF之间的双字节存储。
UTF大小端问题
UTF-16BE,大端:就是把高位字节放在低地址表示。
UTF在文件的存储。UTF格式在文件中总有固定文件头。UTF-8缺省不带BOM。
EF BB BF 表示 UTF-8
FF FE 表示 UTF-16LE
FF FE 00 00 表示 UTF32-LE
iconv命令用来转换文件的编码,如将UTF8编码转换成GB18030的编码,Linux下的iconv开发库包括iconv_open,iconv_close,iconv等C函数,实现快速转换。
iconv -f encoding [-t encoding] [inputfile] ....
-f encoding :字符从encoding编码开始转换
-l:已知的编码字符集合
-c :忽略输出的非法字符
--verbose :显示进度信息
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。
#include <iconv.h>
范例:iconv_t cd = iconv_open(“UTF-8”, “UTF-16”);
范例:iconv_close(cd);
size_t * outbytesleft);
E2BIG:outbuf 没有足够的空间
EINVAL:遇到不完整的多字节序列
GBK 内码查询:
完整的 Unicode 字符集:
Unicode 和 UTF 编码转换:
汉字字符集编码查询:
压缩原理就是找到重复出现的字符串,然后用更短的符号代替,从而达到缩短字符串的目的。本质上,所谓就是找出文件内容的概率分布,将出现概率高的部分代替为更短的形式。内容越重复的文件,可以压缩的越小。如,"ABABABABABABAB"可以压缩成"7AB"。反之内容毫无重复,就很难压缩,极端情况就是,均匀分布的随机字符串,往往一个字符都无法压缩,如任意排列的10个阿拉伯数组(123456789),就无法压缩,再如π,也很难。
∑ log2(1/pn) / n = log2(1/p1)/n + log2(1/p2)/n + ... + log2(1/pn)/n;
(2)假如B文件的每个字节出现的概率是0-255,均匀分布的出现概率是1/256,则 pn = 1/256,计算出极限为 8。
deflate是一种压缩数据流的算法,任何需要流式压缩的地方都可以,deflate是zip压缩文件的默认算法,除了zip文件,还有7z,xz等其他压缩文件,也是用。
(1)不压缩数据,对于已经压缩的数据,不再压缩,这样的数据会稍微增加,但会小于其它应用的一种压缩算法。
(3)先用LZ77,然后再用huffman 编码。压缩树由压缩器生成,并与数据一起存储。
如果数据被分割成不同块,必须使用单一的压缩模式,如果要在这三种压缩模式中相互切换,必须先结束当前块,重新开始一个新的块。
采用字典的方式进行压缩,是一个简单高效的数据压缩算法。把数据中的一些可以组织成短语的字符加入字典,然后再有相同字符出现采用毕节来代替字典中的短语,如此通过标记代替多数重复出现的方式以进行压缩。需先了解 3 个关键词:短语字典,滑动窗口和向前缓冲区。
每次读取数据的时候,先把一部分数据预载入前向缓冲区。为移入滑动窗口做准备
(3) 比如字符(A,B,D) ,可以组合的短语为{(A),(A,B),(A,B,D),(B),(B,D),(D)},如果这些字符在滑动窗口里面,可以标记为当前的短语字典,滑动窗口不断向前滑动,短语字典也不断变化。
(1)找不到匹配时:将未匹配的符号编码成符号标记(多数都是字符本身)
短语标记包含三部分信息:
(2)匹配中的符号个数;
一旦把 n 个符号编码并生成相应的标记,就将这 n 个符号从滑动窗口的一端移出,并用前向缓冲区中同样数量的符号来代替它们,如此,滑动窗口中始终有最新的短语。
B
(4)缓冲区字符(ABCB)在滑动窗口的位移 6 位置找到 AB,成功匹配到短语 AB,将AB 编码为(6,2,C),之所以是 6,是因为窗口的 A 在滑动窗口的索引[6]位置。
(5)缓冲区字符(BABA)在滑动窗口位移 4 的位置匹配到短语 BAB,将 BAB 编码为
(2,2,A)
(7) 缓冲区字符 D,在滑动窗口中没有找到匹配短语,标记为 D
(8)缓冲区中没有数据进入了,结束
6.LZ77解压
(1)开始
(2)符号标记 A 解码
(3)符号标记 B 解码
(4)短语标记(6,2,C)解码。根据 3 中的索引[6]开始,得到 AB,就是重复 AB 再加入上 C,就成了 ABABC,并且滑动窗口滑到最右边的位置。
(5)短语标记(4,3,A)解码
根据5中进行标记。
(7) 符号标记 D 解码
LZ77 压缩算法优点:
解压很快,每个标记都明确告知在哪个位置可以读取。
压缩过程是比较耗时的,因为要花费很多时间寻找滑动窗口中的短语匹配。
6.Huffman 算法原理
先介绍几个概念:码字、码字长度、定长编码与变长编码。
码字长度:这个二进制串的长度称为码字长度。码字长度不变就是固定编码,否则就是变长编码。变长编码可以达到比定长编码好得多的压缩率。其核心思想就是赋予高频字符(出现频率高的字符)短(码字长度较短)码字,赋予低频字符长码字。
哈弗曼会自底向上构造出一棵对应最优编码的二叉树,下面举例来说明。某个文件中有如下字符及其概率。
概率 45 13 12 16 9 5
每个字符都已
在叶子节点用矩形表示,每个叶子节点包含一个字符及其频率。中间节点用圆圈表示,包含其孩子节点的频率之和。中间节点指向左孩子的边标记为 0,指向右孩子的边标记为 1。第6步骤的每个字符的编码都是前缀码。
利用库中的优先级队列实现哈夫曼树,最后基于哈夫曼树最终实现文件压缩。
(2)压缩,实际就是存入压缩编码。利用 Haffman 编码对文件进行压缩,即在压缩文件中按顺序存入每个字符的 Haffman 编码。
(3)将文件中出现的字符以及它们出现的次数写入配置文件中,以便后续压缩使用。
后面的文章会来详细分析代码:
7.deflate 采用的改进版 LZ77 算法
为什么最小匹配3个字节?
deflate 无损压缩解压算法
deflate 中的 huffman 编码:
deflate 中的解压:
读取二进制文件,构建huffmantree 表,读取数据根据huffmantree 生成字符。LZ77 解码需要对窗口生成哈希表(数组+链表),对解压的数据,进行搜索匹配拷贝替换为相应的串即可。
8.gzip 格式分析
GZIP 本身只是一种文件格式,其内部通常采用 DEFLATE 数据格式,而 DEFLATE 采用 LZ77 压缩算法来压缩数据。GZIP 文件由 1 到多个“块”组成,实际上通常只有 1 块。每个块包含头、数据和尾三部分。块的概貌如下:
zlib = zlib 头 + deflate 编码的实际内容 + zlib 尾
(1)头部分
bit 0 FTEXT - 指示文本数据
bit 2 FEXTRA - 指示存在可选项字段
bit 4 FCOMMENT - 指示存在注释字段
MTIME:4 字节。更改时间。
XFL = 2 - 最大压缩但最慢的算法;XFL = 4 - 最快但最小压缩的算法 OS:1 字节。操
0 - FAT 文件系统 (MS-DOS, OS/2, NT/Win32)
2 - VMS/OpenVMS
4 - VM/CMS
6 - HPFS 文件系统 (OS/2, NT)
8 - Z-System
10 - TOPS-20
12 - QDOS
255 - 未知
(若 FLG.FEXTRA = 1)
DEFLATE 数据格式,包含了一系列子数据块。结构如下:
BFINAL:1 比特。0 - 还有后续子块;1 - 该子块是最后一块。BTYPE:2 比特。00 -- 不压缩,01--静态Huffman编码压缩。10--动态Huffman 编码压缩。11--保留。
CRC32:4 字节。原始数据的32位校验和。ISIZE:4 字节。原始数据长度的低32位。
GZIP 中字节排列顺序是 LSB 方式,即 Little-Endian,与 ZLIB 中的相反。
9.zlib 库 API 分析
(1)下载源码包
(2)下载
(3)解压
(3)进入目录
(4)配置
(5)编译
(6)检查,要全部为 yes
(4)安装
基础数据结构:
压缩函数:
deflateInit2:
deflateEnd :压缩完成后,释放空间,注意,仅仅释放deflateInit 中申请的空间,自己申请的空间还是要自己释放。
compress2 : 带 level 的压缩方式。
压缩级别为Z_DEFAULT_COMPRESSION,使用0到9之间的数,1表示最快速度的压缩,9表示最优压缩,0表示不做任何压缩,Z_DEFAULT_COMPRESSION是速度和最优压缩的折衷。
#define Z_NO_COMPRESSION 0 //不压缩
#define Z_BEST_COMPRESSION 9 //压缩优先,但是速度会有些慢
项
成功返回Z_OK,没有足够的内存则返回 Z_MEM_ERROR,若压缩级别无效,返回Z_STREAM_ERROR,版本不兼容则返回 Z_VERSION_ERROR。如果没有错误信息则 msg 被设置为 0。
strm.zalloc = NULL;
strm.opaque = NULL;
strm.next_out = 压缩以后数据存储的 buffer
strm.avail_out = 压缩数据存储 buffer 的长度.
#define Z_DEFLATED 8
*/
windowBits: 窗口比特数
+(15 ~ 8) : 带 zlib 头和尾
> 16 : 带 gzip 头和尾
memLevel: 目前只有一个选项,MAX_MEM_LEVEL,无非是运行过程中对内存使用的限制.
# ifdef MAXSEG_64K
# else
# endif
strategy :用于调整压缩算法,直接给默认就行 Z_DEFAULT_STRATEGY
#define Z_HUFFMAN_onLY 2 //用于强制哈夫曼编码(不做字符匹配)
#define Z_FIXED 4 //阻止使用动态哈夫曼编码,从而允许获得更简单的解码
Z_FILTERED,用于由 filter(或者称为 predictor)生成的数据.过滤的数据包含很多小的随机数据。这种情况下,压缩算法能够获得更好的压缩效果。该选项可以强制更多的哈夫 曼 编 码 和 更 少 的 字 符 匹 配 。 有 时 候 可 以 作 为 Z_DEFAULT_STRATEGY 和
Z_FIXED,阻止使用动态哈夫曼编码,从而允许获得更简单的解码。
strategy 参数只影响压缩比,而不会影响到压缩输出的正确性,因此没有正确的设置也不要紧
deflate函数尽可能压缩数据,当输入缓存为空或输出缓冲满了就会停止,带来输出延迟,除非强行刷新缓冲区。
deflate 会执行下面的一个或者两个动作都执行,avail_in或avail_out 被设置,使用提供更多输入数据和消耗更多输出数据的方式,
(2)next_out 开始提供更多输出数据从而更新 next_out 和 avail_out,如果 flush参数不是为 0 的化这个动作是强制性的,经常性的强制刷新缓存会降低压缩比率,只有必要的时候去设置这个参数。
Z_NO_FLUSH:允许压缩算法累计产生多少数据再输出,以达到压缩率最高。
Z_FINISH:输入和待输出的数据都被处理完,则返回 Z_STREAM_END。如果返回 Z_OK or Z_BUF_ERROR 则需要再次调用 Z_FINISH 直到返回 Z_STREAM_END。
压缩完成后,释放空间,仅仅释放deflateInit 中申请的空间,自己申请的空间还是要自己释放。
解压函数
inflateInit2 :解压初始化的基础函数
inflateEnd :同deflateEnd作用类似
uncompress :解压缩
解压初始化:
windownBits :含义和deflateInit2 一样
解压函数:
z_streamp : 四个参数
strm.next_out = 解压以后数据存储的 buffer
strm.avail_out = 解压数据存储 buffer 的长度
如果是Z_FINISH说明这是最后一包待解压的数据
讲讲对于Nginx而言,怎样去优化。
# 开启 gzipgzip 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-fontobjectfont/ttf font/opentype font/x-woff image/svg+xml;# 是否在 http header 中添加 Vary: Accept-Encoding,建议开启gzip_vary on;# 禁用 IE 6 gzipgzip_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
Default: gzip off;
gzip_buffers:
用于处理请求压缩的缓冲区数量和大小。如32 4K表示按照内存页为单位,建议使用默认值。
Syntax: gzip_buffers number size;
Default: gzip_buffers 32 4k|16 8k;
Context: http, server, location
gzip_comp_level
设置gzip压缩级别,级别越低压缩速度越快,文件压缩比越小。反之速度越慢文件压缩比越大。
Default: gzip_comp_level 1;
Context: http, server, location
gzip_disable
通过表达式,表明哪些 UA 头部使用 gzip 压缩。
Default: —
This directive appeared in version 0.6.23.
gzip_min_length
Syntax: gzip_min_length length;
Context: http, server, location
gzip_http_version
Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
gzip_proxied
Nginx 作为反向代理的时候启用:
expired – 如果 header 中包含 "Expires" 头信息,启用压缩
no-store – 如果 header 中包含 "Cache-Control:no-store" 头信息,启用压缩
no_last_modified – 启用压缩,如果 header 中包含 "Last_Modified" 头信息,
no_etag – 启用压缩,如果 header 中包含 "ETag" 头信息,启用压缩
any – 无条件压缩所有结果数据
| no_etag | auth | any ...;
Context: http, server, location
gzip_types
Syntax: gzip_types mime-type ...;
Context: http, server, location
gzip_vary
AcceptEncoding:gzip,对于本身不支持agip压缩的客户端浏览器有用。
Default: gzip_vary off;
本篇文章就分析到这里,欢迎点赞,收藏,分享。
