Node.js Buffer用法解读


Posted in Javascript onMay 18, 2018

Buffer是什么?

Buffer作为存在于全局对象上,无需引入模块即可使用,你绝对不可以忽略它。

可以理解Buffer是在内存中开辟的一片区域,用于存放二进制数据。Buffer所开辟的是堆外内存。

Buffer的应用场景有哪些?


怎么理解流呢?流是数据的集合(与数据、字符串类似),但是流的数据不能一次性获取到,数据也不会全部load到内存中,因此流非常适合大数据处理以及断断续续返回chunk的外部源。流的生产者与消费者之间的速度通常是不一致的,因此需要buffer来暂存一些数据。buffer大小通过highWaterMark参数指定,默认情况下是16Kb。

存储需要占用大量内存的数据

Buffer 对象占用的内存空间是不计算在 Node.js 进程内存空间限制上的,所以可以用来存储大对象,但是对象的大小还是有限制的。一般情况下32位系统大约是1G,64位系统大约是2G。

如何创建Buffer

除了流自动隐式创建Buffer之外,也可以手动创建Buffer,方式如下:

Buffer中存储的数据已确定

Buffer.from(obj)  // obj支持的类型string, buffer, arrayBuffer, array, or array-like object

注意:Buffer.from不支持传入数字,如下所示:

Buffer.from(1234);

buffer.js:208
  throw new errors.TypeError(
  ^

TypeError [ERR_INVALID_ARG_TYPE]: The "value" argument must not be of type number. Received type number
  at Function.from (buffer.js:208:11)
  ...

若要传入数字可以采用传入数组的方式:

const buf = Buffer.from([1, 2, 3, 4]);
console.log(buf); // <Buffer 01 02 03 04>

但是这种方式存在一个问题,当存入不同的数值的时候buffer中记录的二进制数据会相同,如下所示:

const buf2 = Buffer.from([127, -1]);
console.log(buf2);   // <Buffer 7f ff>

const buf3 = Buffer.from([127, 255]);
console.log(buf3);  // <Buffer 7f ff>

console.log(buf3.equals(buf2)); // true

当要记录的一组数全部落在0到255(readUInt8来读取)这个范围, 或者全部落在-128到127(readInt8来读取)这个范围那么就没有问题,否则的话就强烈不推荐使用Buffer.from来保存一组数。因为不同的数字读取时应该调用不同的方法。

Buffer存储数据未确定

Buffer.alloc、Buffer.allocUnsafe、Buffer.allocUnsafeSlow

Buffer.alloc会用0值填充已分配的内存,所以相比后两者速度上要慢,但是也较为安全。当然也可以通过--zero-fill-buffers flag使allocUnsafe、allocUnsafeSlow在分配完内存后也进行0值填充。

node --zero-fill-buffers index.js

当分配的空间小于4KB的时候,allocUnsafe会直接从之前预分配的Buffer里面slice空间,因此速度比allocUnsafeSlow要快,当大于等于4KB的时候二者速度相差无异。

// 分配空间等于4KB
function createBuffer(fn, size) {
 console.time('buf-' + fn);
 for (var i = 0; i < 100000; i++) {
  Buffer[fn](size);
 }
 console.timeEnd('buf-' + fn);
}
createBuffer('alloc', 4096);
createBuffer('allocUnsafe', 4096);
createBuffer('allocUnsafeSlow', 4096);

// 输出
buf-alloc:      294.002ms
buf-allocUnsafe:   224.072ms
buf-allocUnsafeSlow: 209.22ms
function createBuffer(fn, size) {
 console.time('buf-' + fn);
 for (var i = 0; i < 100000; i++) {
  Buffer[fn](size);
 }
 console.timeEnd('buf-' + fn);
}
createBuffer('alloc', 4095);
createBuffer('allocUnsafe', 4095);
createBuffer('allocUnsafeSlow', 4095);
// 输出
buf-alloc:      296.965ms
buf-allocUnsafe:   135.877ms
buf-allocUnsafeSlow: 205.225ms

需要谨记一点:new Buffer(xxxx) 方式已经不推荐使用了

Buffer使用

buffer转字符串

const buf = Buffer.from('test');
console.log(buf.toString('utf8'));         // test
console.log(buf.toString('utf8', 0, 2));      // te

buffer转json

const buf = Buffer.from([0x1, 0x2, 0x3, 0x4, 0x5]);
console.log(buf.toJSON());  // { type: 'Buffer', data: [ 1, 2, 3, 4, 5 ] }

buffer裁剪,裁剪后返回的新的buffer与原buffer指向同一块内存

buf.slice([start[, end]])
  1. start 起始位置
  2. end 结束位置(不包含)

示例:

var buf1 = Buffer.from('test');
var buf2 = buf1.slice(1, 3).fill('xx');
console.log("buf2 content: " + buf2.toString()); // xx
console.log("buf1 content: " + buf1.toString()); // txxt

buffer拷贝,buffer与数组不同,buffer的长度一旦确定就不再变化,因此当拷贝的源buffer比目标buffer大时只会复制部分的值

buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])

示例:

var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('ABCDEF');

buf1.copy(buf2, 1);
console.log(buf2.toString()); //Abcdef

buffer相等判断,比较的是二进制值

buf.equals(otherBuffer)

示例:

const buf1 = Buffer.from('ABC');
const buf2 = Buffer.from('414243', 'hex'); 
console.log(buf1.equals(buf2));  // true

除了equals之外,compare其实也可以用于判断是否相等(当结果为0则相等),不过compare更主要的作用是用于对数组内的buffer实例排序。

buffer是否包含特定值

buf.includes(value[, byteOffset][, encoding])
buf.indexOf(value[, byteOffset][, encoding])

示例:

const buf = Buffer.from('this is a buffer');
console.log(buf.includes('this')); // true
console.log(buf.indexOf('this')); // 0

写入读取数值

写入方法:

位数固定且超过1个字节的: write{Double| Float | Int16 | Int32|  UInt16 | UInt32 }{BE|LE}(value, offset)

位数不固定的: write{Int | UInt}{BE | LE}(value, offset, bytelength) //此方法提供了更灵活的位数表示数据(比如3位、5位)

位数固定是1个字节的:     write{Int8 | Unit8}(value, offset)

读取方法:

位数固定且超过1个字节的: read{Double| Float | Int16 | Int32 | UInt16 | UInt32 }{BE|LE}(offset)

位数不固定的:  read{Int | UInt}{BE | LE}(offset, byteLength)

位数固定是1个字节的: read{Int8 | Unit8}(offset)

Double、Float、Int16、Int32、UInt16、UInt32既确定了表征数字的位数,也确定了是否包含负数,因此定义了不同的数据范围。同时由于表征数字的位数都超过8位,无法用一个字节来表示,因此就涉及到了计算机的字节序区分(大端字节序与小端字节序)

关于大端小端的区别可以这么理解:数值的高位在buffer的起始位置的是大端,数值的低位buffer的起始位置则是小端

const buf = Buffer.allocUnsafe(2);
buf.writeInt16BE(256, 0) 
console.log(buf);      // <Buffer 01 00> 
buf.writeInt16LE(256, 0)
console.log(buf);      // <Buffer 00 01>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery indexOf使用方法
Aug 19 Javascript
一个简单的JS时间控件示例代码(JS时分秒时间控件)
Nov 22 Javascript
基于jQuery的JavaScript模版引擎JsRender使用指南
Dec 29 Javascript
基于jQuery的Web上传插件Uploadify使用示例
May 19 Javascript
Angular 1.x个人使用的经验小结
Jul 19 Javascript
vue使用drag与drop实现拖拽的示例代码
Sep 07 Javascript
微信小程序获取手机系统信息的方法【附源码下载】
Dec 07 Javascript
webpack项目调试以及独立打包配置文件的方法
Feb 28 Javascript
vue.js使用v-if实现显示与隐藏功能示例
Jul 06 Javascript
Javascript中绑定click事件的四种方式介绍
Oct 26 Javascript
浅谈React Native 传参的几种方式(小结)
May 21 Javascript
Vant 在vue-cli 4.x中按需加载操作
Nov 05 Javascript
从零开始搭建webpack+react开发环境的详细步骤
May 18 #Javascript
Bootstrap table中toolbar新增条件查询及refresh参数使用方法
May 18 #Javascript
webpack4 css打包压缩问题的解决
May 18 #Javascript
微信小程序实现长按删除图片的示例
May 18 #Javascript
解决Vue中mounted钩子函数获取节点高度出错问题
May 18 #Javascript
Vue数据双向绑定原理及简单实现方法
May 18 #Javascript
Swiper 4.x 使用方法(移动端网站的内容触摸滑动)
May 17 #Javascript
You might like
php+javascript实现的动态显示服务器运行程序进度条功能示例
2017/08/07 PHP
php生成毫秒时间戳的实例讲解
2017/09/22 PHP
一些有关检查数据的JS代码
2006/09/07 Javascript
收藏一些不常用,但是有用的代码
2007/03/12 Javascript
IE下window.onresize 多次调用与死循环bug处理方法介绍
2013/11/12 Javascript
js动态添加删除,后台取数据(示例代码)
2013/11/25 Javascript
控制input输入框中提示信息的显示和隐藏的方法
2014/02/12 Javascript
js实现的Easy Tabs选项卡用法实例
2015/09/06 Javascript
解决Angular.Js与Django标签冲突的方案
2016/12/20 Javascript
Angular的MVC和作用域
2016/12/26 Javascript
Sublime Text新建.vue模板并高亮(图文教程)
2017/10/26 Javascript
谈谈JS中的!!
2017/12/07 Javascript
高性能的javascript之加载顺序与执行原理篇
2018/01/14 Javascript
Vue实现自定义下拉菜单功能
2018/07/16 Javascript
JavaScript设计模式之构造器模式(生成器模式)定义与用法实例分析
2018/07/26 Javascript
bootstrap table.js动态填充单元格数据的多种方法
2019/07/18 Javascript
关于layui 下拉列表的change事件详解
2019/09/20 Javascript
微信小程序pinker组件使用实现自动相减日期
2020/05/07 Javascript
python进阶教程之词典、字典、dict
2014/08/29 Python
11月编程语言排行榜 Python逆袭C#上升到第4
2017/11/15 Python
Python二叉树的遍历操作示例【前序遍历,中序遍历,后序遍历,层序遍历】
2018/12/24 Python
Python多图片合并PDF的方法
2019/01/03 Python
Pytorch 扩展Tensor维度、压缩Tensor维度的方法
2020/09/09 Python
python中的垃圾回收(GC)机制
2020/09/21 Python
Pycharm安装第三方库失败解决方案
2020/11/17 Python
python re模块常见用法例举
2021/03/01 Python
Anthropologie英国:美国家喻户晓的休闲服装和家居产品品牌
2018/12/05 全球购物
护理专业学生的求职信范文
2013/12/11 职场文书
幼儿园庆六一游园活动方案
2014/01/29 职场文书
劲霸男装广告词
2014/03/21 职场文书
药学职务聘任书
2014/03/29 职场文书
授权委托书范本
2014/04/03 职场文书
班级体育活动总结
2014/07/05 职场文书
党员四风剖析材料
2014/08/27 职场文书
戒毒悔改检讨书
2014/09/21 职场文书
教师节大会主持词
2015/07/06 职场文书