base-122编码,比base-64更加高效
这是一种比base-64更加节省空间的编码方式。github地址
1.概述
在网络编程中,我们常需要利用一些文本传输协议(如POP3和SMTP)协议来传输二进制数据。
这时候必须要先将它们转化为文本格式才能进行传输,最常用的编码方式就是base-64。它虽然简单方便,容易实现,但是将会带来33%的数据量增长。
2.一个小例子
有些时候我们想把图片、字体、音频等二进制文件作为url的一部分传输给客户端/服务器,这样可以减少一次请求和响应。当然,我们必须保证这些文件不能太大。
比如,原来是这样写的:

为了避免这次额外的资源请求,我们可以利用base-64编码从而换成下面的写法:
虽然这种做法可能对于小文件来说确实可以优化整个数据传输的效率,但是如果不慎用于大文件将很可能导致性能的下降。原因就是base-64编码会导致额外增加33%的传输量。下面讲简要分析其原因。
3.base-64编码
base-64是将二进制数据转换为文本数据的最常用方法,比如说要把一个字节的二进制数据–01101001插入到一个文本文件中。最直接的方法就是找两个字符分别与0、1对应,如果我们选择的是A和B,那么转换的结果就是下面这样的(假设这是一个只有1个像素的图片文件)。

虽然实现起来很简单,但是编码后的数据会变为原来的八倍。
对于base-64,他会把数据按照每6个位分为一组(一共有64种组合方式),每种组合方式(编号为0~63)各对应一个字符,然后进行编码。这样转换前后的数据量之比就为8:6。
如果原数据的数据量(以位为单位计算)不是6的倍数,添加1个或2个额外的字节来凑足24位,然后分成3组后再对应编码。但是这1个或2个额外添加的字节不参与编码,而是最后统一转换成1个或2个=号。
那么,如果使用base-64来编码上面的图片文件,结果将变成:

base-64编码使用的字符包括26个大写字母+26个小写字母+10个阿拉伯数字,最后还有两个特殊符号+和/。
为了改良base-64,我们可以考虑使用其他的编码字符,但是ASCII的限制太多,很难再找到更加高效并且简单可行的映射关系,所以我们下面尝试在UTF-8中寻找解决方案。
4.UTF-8编码
因为大部分的网页文件(尤其是有汉字的)其实是由UTF-8编码而成的,所以我们的想法是完全可行的。
下面我们开始介绍关于UTF-8的一些核心概念。
UTF-8是一种对于Unicode的可变长字符编码方式,一共支持1,112,064个符号点。所谓符号点,其实就是可以表示为一个字符的数字(在Unicode中,并不是所有的数字都可以转换表示成一个字符)。对于ASCII字符的编码,可以只用一个字节;但是对于某些的符号点,就可能需要使用多达4个字节来表示这个字符。
| Unicode中符号点的范围 | UTF-8编码 | 所用的总位数 | 符号点所占的位数 | 增加率 |
|---|---|---|---|---|
| 0x00 – 0x7F | 0xxxxxxx | 8 | 7 | 8:7 |
| 0x80 – 0x7FF | 110xxxxx 10xxxxxx | 16 | 11 | 16:11 |
| 0x800 – 0xFFFF | 1110xxxx 10xxxxxx 10xxxxxx | 24 | 16 | 24:16 |
| 0x10000 – 0x10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 32 | 21 | 32:21 |
上面的增加率,就是表示该范围内的符号数所用的位数和实际上真正有效的位数(其他的位只是作为辅助标识)。
如果使用上表中的单字节编码方式来将我们的二进制数据转换成UTF-8编码,那么结果将会是下面这样子的:
如果使用这种每7位1组的编码方式,那么编码之后得到的数据量将从base64的8:6下降为8:7。
但是很遗憾,如果在网页中使用这种编码方式,将会引起冲突,不然base64也不会从ASCII编码字符只中选取其中的64个作为目标字符,原因还是为了避免在网页解析时发生冲突。
比如,我们转换后的数据一般是以下面这种形式出现在网页代码中的:
(如果数据中出现",这个字符就可能使浏览器误以为是字符串的结束,进而造成数据截断)。
5.如何避免冲突
为了保证编码后得到的字符不会在HTML页面中引起冲突,我们需要找出所有的“不安全”的字符。(比如双引号")
除了双引号"以外,还有换行字符\n、回车字符\r、转义字符\和&、不可显示的null字符–0x00都会引起解析冲突。
这样,把上面的6个”不安全“字符剔除后,只剩下122个字符。
6.base-122编码
这样我们的方案基本成型了,将原二进制数据按照每7位为一组(如果数据长度不是7的倍数,则需要填充),然后直接转换为UTF-8中的单字节字符,0xxxxxxx。
如果转换后的字符不凑巧就是6个“不安全”的字符之一,则做进一步的转换,将其变成双字节的UTF-8字符:110xxxxx 10xxxxxx。因为只有6个字符,其实只需要3个位就行了,这里我们使用sss来表示这些实际有效的数据位,110sssxx 10xxxxxx。
那么剩下来还有8个位可以存放数据,这8个位完全足够存放下一组的7个位的数据。这样我们选后面的7位来存放下一组的数据即可,110sss1x 10xxxxxx(sss用来标识不安全的6个字符,xxxxxxx用来存放下一组的数据)。
base-122编码的最终效果如下:
终于,我们完成了编码前后数据比为7:8的目标,编码同样的数据,所占用的数据量是base-64的86%。
7.如何使用
使用前必须保证你的HTML文件使用的是UTF-8编码格式。
用法见github首页的介绍。
https://github.com/kevinAlbs/Base122
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
