Buffer 做为 nodejs 中重要的概念和功能,为开发者提供了操做二进制的能力。本文记录了几个问题,来加深对 Buffer 的理解和使用:javascript
🔍 关注公众号“心谭博客” / 👉 查看原文: xxoo521.com / 欢迎交流和指正html
Buffer 是 nodejs 核心 API,它提供咱们处理二进制数据流的功能。Buffer 的使用和 ES2017 的 Uint8Array 很是类似,但因为 node 的特性,专门提供了更深刻的 api。java
Uint8Array 的字面意思就是:8 位无符号整型数组。一个字节是 8bit,而字节的表示也是由两个 16 进制(4bit)的数字组成的。node
const buf = Buffer.alloc(1);
console.log(buf); // output: <Buffer 00>
复制代码
Buffer 能够跳出 nodejs 对堆内内存大小的限制。nodejs12 提供了 4 种 api 来申请堆外内存:api
Buffer.from()
Buffer.alloc(size[, fill[, encoding]])
Buffer.allocUnsafe(size)
Buffer.allocUnsafeSlow(size)
在申请内存时,可能这片内存以前存储过其余数据。若是不清除原数据,那么会有数据泄漏的安全风险;若是清除原数据,速度上会慢一些。具体用哪一种方式,根据实际状况定。数组
根据提供的 api,能够手动实现一个alloc
:安全
function pollifyAlloc(size, fill = 0, encoding = "utf8") {
const buf = Buffer.allocUnsafe(size);
buf.fill(fill, 0, size, encoding);
return buf;
}
复制代码
从命名上能够直接看出效果,Buffer.allocUnsafeSlow
更慢。由于当使用 Buffer.allocUnsafe
建立新的 Buffer 实例时,若是要分配的内存小于 4KB,则会从一个预分配的 Buffer 切割出来。 这能够避免垃圾回收机制因建立太多独立的 Buffer 而过分使用。函数
这种方式经过消除跟踪和清理的须要来改进性能和内存使用。性能
利用 Buffer,能够得到数据的真实所占字节。例如一个汉字,它的字符长度是 1。但因为是 utf8 编码的汉字,因此占用 3 个字节。ui
直接利用Buffer.byteLength()
能够得到字符串指定编码的字节长度:
const str = "本文原文地址: xxoo521.com";
console.log(Buffer.byteLength(str, "utf8")); // output: 31
console.log(str.length); // output: 19
复制代码
也能够直接访问 Buffer 实例的 length 属性(不推荐):
console.log(Buffer.from(str, "utf8").length); // output: 31
复制代码
Nodejs 当前支持的编码格式有:ascii、utf八、utf16le、ucs二、base6四、latin一、binary、hex。其余编码须要借助三方库来完成。
下面,是用Buffer.from()
和buf.toString()
来封装的 nodejs 平台的编码转换函数:
function trans(str, from = "utf8", to = "utf8") {
const buf = Buffer.from(str, from);
return buf.toString(to);
}
// output: 5Y6f5paH5Zyw5Z2AOiB4eG9vNTIxLmNvbQ==
console.log(trans("原文地址: xxoo521.com", "utf8", "base64"));
复制代码
在生成 Buffer 实例,操做二进制数据的时候,千万要注意接口是基于共享内存,仍是基于拷贝底层内存。
例如对于生成 Buffer 实例的from()
,不一样类型的参数,nodejs 底层的行为是不一样的。
为了更形象地解释,请看下面两段代码。
代码 1:
const buf1 = Buffer.from("buffer");
const buf2 = Buffer.from(buf1); // 拷贝参数中buffer的数据到新的实例
buf1[0]++;
console.log(buf1.toString()); // output: cuffer
console.log(buf2.toString()); // output: buffer
复制代码
代码 2:
const arr = new Uint8Array(1);
arr[0] = 97;
const buf1 = Buffer.from(arr.buffer);
console.log(buf1.toString()); // output: a
arr[0] = 98;
console.log(buf1.toString()); // output: b
复制代码
在第二段代码中,传入Buffer.from
的参数类型是arrayBuffer
。所以Buffer.from
仅仅是建立视图,而不是拷贝底层内存。buf1 和 arr 的内存是共享的。
在操做 Buffer 的过程当中,须要特别注意共享和拷贝的区别,发生错误比较难排查。