Skip to content

Buffer 二进制 Base64 #3

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编/解码实现

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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