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 相关文章推荐
js 判断图片是否加载完以及实现图片的预下载
Aug 14 Javascript
javascript实现禁止复制网页内容
Dec 16 Javascript
jQuery实现带滚动导航效果的全屏滚动相册实例
Jun 19 Javascript
浅析jQuery Ajax请求参数和返回数据的处理
Feb 24 Javascript
jQuery实现三级菜单的代码
May 09 Javascript
noty ? jQuery通知插件全面解析
May 18 Javascript
微信JS-SDK自定义分享功能实例详解【分享给朋友/分享到朋友圈】
Nov 25 Javascript
js canvas实现画图、滤镜效果
Nov 27 Javascript
vue数据操作之点击事件实现num加减功能示例
Jan 19 Javascript
elementUI多选框反选的实现代码
Apr 03 Javascript
JavaScript简单编程实例学习
Feb 14 Javascript
vue从零实现一个消息通知组件的方法详解
Mar 16 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
一个用于网络的工具函数库
2006/10/09 PHP
destoon实现调用当前栏目分类及子分类和三级分类的方法
2014/08/21 PHP
php实现两表合并成新表并且有序排列的方法
2014/12/05 PHP
PHP聊天室简单实现方法详解
2018/12/08 PHP
YII2框架中添加自定义模块的方法实例分析
2020/03/18 PHP
怎么让脚本或里面的函数在所有图片都载入完毕的时候执行
2006/10/17 Javascript
JQuery下的Live方法和$.browser方法使用代码
2010/06/02 Javascript
javascript学习笔记(十八) 获得页面中的元素代码
2012/06/20 Javascript
JS合并数组的几种方法及优劣比较
2014/09/19 Javascript
js实现文本框支持加减运算的方法
2015/08/19 Javascript
js显示当前日期时间和星期几
2015/10/22 Javascript
javascript创建对象的几种模式介绍
2016/05/06 Javascript
JavaScript接口的实现三种方式(推荐)
2016/06/14 Javascript
jQuery设置和获取select、checkbox、radio的选中值方法
2017/01/01 Javascript
原生JS实现图片无缝滚动方法(附带封装的运动框架)
2017/10/01 Javascript
基于Axios 常用的请求方法别名(详解)
2018/03/13 Javascript
利用Vue构造器创建Form组件的通用解决方法
2018/12/03 Javascript
js中实例与对象的区别讲解
2019/01/21 Javascript
JS实现的冒泡排序,快速排序,插入排序算法示例
2019/03/02 Javascript
layui之table checkbox初始化时选中对应选项的方法
2019/09/02 Javascript
layui给下拉框、按钮状态、时间赋初始值的方法
2019/09/10 Javascript
JS实现简单日历特效
2020/01/03 Javascript
jQuery实现B2B网站后台管理系统侧导航
2020/07/08 jQuery
解决vant title-active-color与title-inactive-color不生效问题
2020/11/03 Javascript
状态机的概念和在Python下使用状态机的教程
2015/04/11 Python
Python批量查询关键词微信指数实例方法
2019/06/27 Python
python统计指定目录内文件的代码行数
2019/09/19 Python
通俗易懂了解Python装饰器原理
2020/09/17 Python
在pycharm中使用pipenv创建虚拟环境和安装django的详细教程
2020/11/30 Python
HTML5移动端开发中的Viewport标签及相关CSS用法解析
2016/04/15 HTML / CSS
Ticketmaster意大利:音乐会、节日、艺术和剧院的官方门票
2019/12/23 全球购物
环境科学专业个人求职的自我评价
2013/11/28 职场文书
工业自动化专业自荐信范文
2014/04/10 职场文书
青年安全生产示范岗事迹材料
2014/05/04 职场文书
雏鹰争章活动总结
2014/05/09 职场文书
清洁工工作总结
2015/08/11 职场文书