Skip to content

Buffer 二进制 Base64 #3

@pkjy

Description

@pkjy

Buffer 二进制 Base64

Buffer

Buffer是V8引擎上的扩展,这意味着它有其固有的一些限制。Buffer实际上是对内存的直接分配,这意味着这多少受制于你在低级计算机语言方面的经验。JavaScript的其他数据类型都把存储数据的复杂性进行了抽象,而Buffer与它们不同,它提供的是内存的直接操作。创建了一个Buffer后,它的大小就固定了。如果你需要添加更多的数据,就必须把老的Buffer复制到一个更大的Buffer中。虽然有些特性看起来让人沮丧,但它们让Buffer能够在服务器上快速地处理大量的数据操作。这是一个特意的设计选择,为了性能而牺牲了一些程序员的开发便利。 -《Node即学即用》4.3.3 Buffer

简单来说,Buffer是Node提供给我们直接操作二进制数据的类。

二进制

简介

大多数人都知道,计算机的工作原理是操作“开”和“关”状态。因为只有这样两种状态,所以我们称此为二元状态。计算机的所有东西都建立在此基础上,这就说明了为什么在计算机上操作时,直接操作二进制通常是最快的方法。要做更复杂的事情时,我们把比特(bit,每一位表示一个二元状态)集合成8个一组,称之为8位组(octet),也就是通常所说的字节(byte)。1这样我们就能表示除了0、1外的其他数字了。-《Node即学即用》4.3.3 Buffer

8位bit = 1个byte

利用8位字节,我们就可以表示从0到255间的所有数字了。

128 64 32 16 8 4 2 1
0 0 0 0 0 0 0 0 = 0
- - - - - - - -
128 64 32 16 8 4 2 1
1 1 1 1 1 1 1 1 = 255
- - - - - - - -
128 64 32 16 8 4 2 1
1 0 0 1 0 1 0 1 =149

转化的算法就不多加赘述了,高中都有学.. 比如149 = 1x2^7+0x2^6+0x2^5+1x2^4+0x2^3+1x2^2+0x2^1+1x2^0

但是8个0和1组成的字符串来描述实在是不方便,所以**十六进制(HEX)**表示法便流行起来。二进制表示法的基数是2,因此每个数字(0或1)只有两种状态。十六进制使用的基数是16,每一位能够表示0到F种状态,其中字母A到F(或对应的小写字母)对应代表10到15。这样只需要2个字母就能表示整个字节了。最右的位表示1,往左一位就表示16。如果我们要表示数字149,就等价于(16 x 9)+(5 x 1),也就是十六进制的95。

十六进制转换到十进制:

0 1 2 3 4 5 6 7 8 9 A B C D E F
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

十六位进制法计数:

16 1
0 0 = 0
16 1
F F = 255
16 1
9 5 = 149

在JavaScript中,用一个十六进制值表示数字时,需要在其十六进制数值前添加0x标记。比如,0x95表示十进制数字149。在Node里,你会常常看见console.log()输出,或是在Node命令行中,Buffer值是采用十六进制表示的。下面表格就演示了如何用Buffer保存3个字符(比如RGB颜色值)。

> new Buffer([255,0,149]);
<Buffer ff 00 95>
>

Node中创建Buffer默认是UTF-8编码的。

Base64

Base64编码原理

Base64编码是基于64个字符A-Z,a-z,0-9,+,/的编码方式,因为2的6次方正好为64,所以就用6bit就可以表示出64个字符,eg:000000对应A,000001对应B。

**BASE64 的编码原理:**都是按字符串长度,以每 3 个 字符(1Byte=8bit)为一组,然后针对每组,首先获取每个字符的 ASCII 编码(字符'a'=97=01100001),然后将 ASCII 编码转换成 8 bit 的二进制,得到一组 3 * 8=24 bit 的字节。然后再将这 24 bit 划分为 4 个 6 bit 的字节,并在每个 6 bit 的字节前面都填两个高位 0,得到 4 个 8 bit 的字节,然后将这 4 个 8 bit 的字节转换成十进制,对照 BASE64 编码表 (下表),得到对应编码后的字符。
image

注:1. 要求被编码字符是8bit的,所以须在ASCII编码范围内,\u0000-\u00ff,中文就不行。2. 如果被编码字符长度不是3的倍数的时候,则都用0代替,对应的输出字符为“=”

Base64编码本质上是一种将二进制数据转成文本数据的方案。对于非二进制数据,是先将其转换成二进制形式,然后每连续6比特(2的6次方=64)计算其十进制值,根据该值在A--Z,a--z,0--9,+,/ 这64个字符中找到对应的字符,最终得到一个文本字符串。基本规则如下几点:

  1. 标准Base64只有64个字符(英文大小写、数字和+、/)以及用作后缀等号;
  2. Base64是把3个字节变成4个可打印字符,所以Base64编码后的字符串一定能被4整除(不算用作后缀的等号);
  3. 等号一定用作后缀,且数目一定是0个、1个或2个。这是因为如果原文长度不能被3整除,Base64要在后面添加\0凑齐3n位。为了正确还原,添加了几个\0就加上几个等号。显然添加等号的数目只能是0、1或2;
  4. 严格来说Base64不能算是一种加密,只能说是编码转换。

Base64解码原理

解码原理是将4个字节转换成3个字节.先读入4个6位(用或运算),每次左移6位,再右移3次,每次8位,这样就还原了。

Base64编码字符串实例

1、字符长度为能被3整除时:比如“Tom” :

T o m
ASCII: 84 111 109
8bit字节: 01010100 01101111 01101101
6bit字节: 010101 000110 111101 101101
十进制: 21 6 61 45
对应编码: V G 9 t

所以,“Tom”的 BASE64 编码结果为 VG9t。

image

2、字符串长度不能被3整除时,比如“Lucy”:

L u c y
ASCII: 76 117 99 121
8bit字节: 01001100 01110101 01100011 01111001 00000000 00000000
6bit字节: 010011 000111 010101 100011 011110 010000 000000 000000
十进制: 19 7 21 35 30 16 异常 异常
对应编码: T H V j e Q = =

因为4个Base编码为一组,最后再补上'='补齐,即:THVjeQ==

image

ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。

ASCII码表可参考《标准表》

Base64编码的应用

  1. 实现简单的数据加密,使用户一眼望去完全看不出真实数据内容,base64算法的复杂程度要小,效率要高相对较高。

  2. Base64编码的主要的作用不在于安全性,而在于让内容能在各个网关间无错的传输,这才是Base64编码的核心作用。

  3. 在计算机中任何数据都是按ascii码存储的,而ascii码的128~255之间的值是不可见字符。而在网络上交换数据时,比如说从A地传到B地,往往要经过多个路由设备,由于不同的设备对字符的处理方式有一些不同,这样那些不可见字符就有可能被处理错误,这是不利于传输的。所以就先把数据先做一个Base64编码,统统变成可见字符,这样出错的可能性就大降低了。

  4. Base64 编码在URL中的应用:

  • Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
  • 然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。

Base64具体实现

  1. 浏览器环境:
  • Base64编码:window.btoa('content')
  • Base64解码:window.atob('content')
  1. Node:

参考资料:

待办

  • Node的Base64编/解码实现

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions