Buffer
对于一个前端攻城狮,如果你想学习 nodejs ,在这条路上,buffer 将是一个困扰你的玩意,因为在操作 buffer 时,会存在各种各样的编码问题。这在你以前的前端工作中是没有的或者是很少见的,今天我们就来巴拉巴拉 Buffer 这个玩意,不求彻底搞懂,只求搞清楚他是干嘛的,应该怎么用。
1.1 Buffer 结构
Buffer 是一个像 Array 的对象,但它主要是用来操作字节的。
1.2 Buffer 对象
Buffer 类似于数组,他的每个元素是由两个 16 进制的数字组成,即 0 到 255 的数值。下面是一个简单的代码演示:
var str = "我的世界hello";
var buf = new Buffer(str,"utf-8");
console.log(buf);
结果:<Buffer e6 88 91 e7 9a 84 e4 b8 96 e7 95 8c 68 65 6c 6c 6f>
可以看到,不同编码的字符串占用的元素个数各不相同,上面代码中的中文在 UTF-8 编码下占 3 个元素,字母占用了 1 个元素。
Buffer 受 Array 的影响很大,可以访问他的 length 属性,也可以通过下标访问元素,在构造对象时也十分相似,看代码:
var buf = new Buffer(100);
console.log(buf.length) // 100
上述代码分配了长100 字节的 Buffer 。这里就可以通过下标访问 Buffer 中的元素:
console.log(buf[20]);
这里打印得到的结果是不确定的,他是一个 0 到 255 的随机数。
同样的,我们也可以通过下标对其进行赋值:
buf[10] = 100;
console.log(buf[10]) // 100
这里还有一个有趣的情况,当你给 buf 元素赋的值不在 0 到 255 之间或者给他个小数的值呢?如果是这种情况, Buffer 会自己做简单的处理,规则如下:
- 当你的赋值小于 0 时,就将该值逐次加 256 ,直到值是一个 0 到 255 之间的整数。
- 如果值大于 255 时,就将该值逐次减 256, 直到值是一个 0 到 255 之间的整数。
- 如果是小数,则舍弃掉小数部分,只保留整数部分
1.3 Buffer 内存分配
简单的说,Buffer 采用的是一种内存的动态管理机制。也就是说,他会预先就设定好一块固定大小的内存区域(叫做 slab)。这个区域存在这三种状态:
- full:完全分配状态(全部使用)
- partial :部分分配状态
- empty: 没有分配状态 (没有使用)
当我们需要一个 Buffer 对象时,我们可以直接在创建时就指定大小:
new Buffer(size);
Node 以 8 KB 为界限来区分 Buffer 是大对象还是小对象:
Buffer.poolSize = 8*1024
这个 8KB 就是预先分配的固定内存的大小,在我们使用时,会以它作为单元单位进行内存分配。(这里需要说明一下,只要你在创建的时候设置了Buffer 的大小,那么你就不能再改变他的大小)
1. 分配小 Buffer 对象
如果指定的 Buffer 的大小小于 8KB,Node 会按照小对象的方式进行分配。Buffer 的分配过程重要是使用一个局部变量 pool 作为中间对象处,处于分配状态的内存单元会指向他。以下是分配一个全新的slab 单元的操作,他将会申请新的 SlowBuffer 对象指向它:
var pool;
function allocPool(){
pool = new SlowBuffer(Buffer.poolSize);
pool.used = 0;
}
然后将创建的 Buffer 对象一个一个的放进这个创建的小 Buffer中,直到他处于full 状态才会继续创建新的slab单元。如果第二次创建的Buffer对象比当前这个 slab 时,就不会继续在这个pool中储存,会重新的分配一个 slab,这样子原来的slab的剩余空间就被浪费掉了。
2.分配大 Buffer 对象
如果你创建的 Buffer 对象大于 8Kb,则会将一个 SlowBuffer 对象作为slab,这个slab将会被这个大Buffer 对象独占。
2.1 Buffer 转换
Buffer 对象可以与字符串之间互相转换。目前支持的字符编码类型有如下几种:
- ASCII
- UTF-8
- UTF-16LE/UCS-2
- Base64
- Binary
- Hex
2.2 字符串转Buffer
字符串转 Buffer 主要是通过构造函数完成的:
new Buffer(str,[encoding])
一个 Buffer 对象可以储存不同编码类型的字符串转码的值,调用 write() 方法可以实现该目标。
buf.write(str,[offset],[length],[encoding])
虽然你可以这样子做,但是你要当心每种编码的字节长度不同,将 Buffer 反转回字符串的时候需要谨慎的处理。·
2.2 Buffer 转字符串
将 Buffer 转回字符串得操作也很简单,是用Buffer对象的 toString() 可以将Buffer 对象转换为字符串,代码如下:
buf.toString([encoding],[start],[end])