接触node后,少不了会对文件进行操做,因而你可能会遇到如下问题:html
"arrayBuffer"
,那arrayBuffer
是什么呢?buffer
。好比使用fs.readFile()
去读文件时,第一个参数的类型是能够是Buffer
,那Buffer
是什么呢?TypedArray
,那TypedArray
又是什么呢?若是你对这三个问题的答案了然于心,那么接下来的文章能够不用看了。若是有疑问的话,能够往下看,说不定就能帮你解决疑问。java
首先你须要了解一下二进制数组,这对于咱们搞明白上面三个问题很是重要。node
是什么:用于处理二进制数据的类。es6
为何存在:javaScript
与显卡通讯的时候,大量的实时的数据交互,用文本格式须要进行格式转化,二进制则省去转化时间。api
和数组的关系:buffer
的实例相似与整数数组,可是buffer
的大小是固定不变的。数组
二进制数组由三类对象组成:网络
Uint8Array
(无符号 8 位整数)数组视图, Int16Array
(16 位整数)数组视图, Float32Array
(32 位浮点数)数组视图等等。一波硬解答:函数
ArrayBuffer
对象表明原始的二进制数据TypedArray
视图用来读写简单类型的二进制数据(ArrayBuffer),DataView
视图用来读写复杂类型的二进制数据(ArrayBuffer)。Buffer
类是以更优化和更适合Nodejs的方式实现了Unit8Array
API,意思就是Buffer
类实际上是TypedArray(Unit8Array)
的nodejs实现。至此,上面三个问题应该都解决了。想了解更多的能够继续往下看。优化
ArrayBuffer
对象表明储存二进制数据的一段内存,它不能直接读写,只能经过视图进行操做。ui
ArrayBuffer
也是一个构造函数,能够分配一段能够存放数据的连续内存
const buffer = new BufferAarray(12); // 生成一个能够12个字节的连续内存,每一个字节的默认值是0
复制代码
以DataView视图方式读取
const buffer = new BufferAarray(12);
const dataView = new DataView(buffer); // 对一段12字节的内存创建DataView视图
dataView.getUnit8(0); // 0 以Unit8方式读取第一个字节
复制代码
以TypedArray视图方式读取,和DataView不一样的是DataView是一个构造函数,TypedArray则是一组构造函数
const buffer = new BufferAarray(12);
const x1 = new Unit8Array(buffer); // 创建Unit8Array视图
const x2 = new Int32Array(buffer); // 创建Int32Array视图
x1[0] = 1;
x2[0] = 2;
// 因为两个视图是对应的是同一段内存,因此其中一个视图更改了内存,会影响到另外一个视图
x1[0]; // 2
复制代码
ArrayBuffer对象还拥有byteLength属性和slice方法(此方法是ArrayBuffer对象上惟一能够读写内存的方法)。
ArrayBuffer有一个静态方法isView,判断参数是否为视图实例。
const buffer = new ArrayBuffer(12);
buffer.byteLength; // 12
buffer.slice(0, 3); // 用法和数组一致,拷贝buffer的前三个字节生成一个新的ArrayBuffer对象
ArrayBuffer.isView(buffer); // false
const dataView = new DataView(buffer);
ArrayBuffer.isView(dataView); // true
复制代码
因为视图的构造函数能够指定起始位置和长度,因此在同一段内存之中,能够依次存放不一样类型的数据,这叫作“复合视图”。
const buffer = new ArrayBuffer(12);
const a = new Unit8Array(buffer, 0, 1); // 以Unit8Array读取第一个字节
a[0] = 1;
const b = new Int32Array(buffer, 1, 2); // 以Int32Array读取第二个字节
b[0] = 2;
复制代码
视图是什么:ArrayBuffer对象能够存储多种类型的数据。不一样类型的数据有不一样的解读方式,这就叫视图
视图的做用:以指定格式解读二进制数据
TypedArray一共包含九种类型,每一种都是一个构造函数。(DataView视图支持除Unit8ClampedArray之外的八种)
名称 | 占用字节 | 描述 |
---|---|---|
Int8Array | 1 | 8位有符号整数 |
Uint8Array | 1 | 8位无符号整数 |
Uint8ClampedArray | 1 | 8位无符号整型固定数组(数值在0~255之间) |
Int16Array | 2 | 16位有符号整数 |
Uint16Array | 2 | 16位无符号整数 |
Int32Array | 4 | 32 位有符号整数 |
Uint32Array | 4 | 32 位无符号整数 |
Float32Array | 4 | 32 位 IEEE 浮点数 |
Float64Array | 8 | 64 位 IEEE 浮点数 |
cancat
方法若是一段数据包含多种类型的数据,除了使用复合视图的方式读取以外,还可使用DataView视图读取。
DataView
视图提供更多操做选项,并且支持设定字节序。原本,在设计目的上,ArrayBuffer
对象的各类TypedArray
视图,是用来向网卡、声卡之类的本机设备传送数据,因此使用本机的字节序就能够了;而DataView
视图的设计目的,是用来处理网络设备传来的数据,因此大端字节序或小端字节序是能够自行设定的。
大端字节序和小端字节序,x68系统使用小端字节序,123456中12比较重要,因此排在后面,存储顺序是563412。大端则相反
一系列get方法用来读取内存
const buffer = new ArrayBuffer(24);
const dv = new DataView(buffer);
// 接受一个参数
const v1 = dv.getUnit8(0); // 从第一个字节读取一个8位无符号整数
// 读两个字节以上时,须要明确数据的存储模式(true:小端/false:大端)
const v1 = dv.getUint16(1, true); // 从第二个字节开始,读取一个16位无符号整数(长度两个字节)
复制代码
一些列set方法用来写入内存
// 接受三个参数,1.字节序号,2.写入的数据,3.写入方式(true:小端/false|undeifined:大端)
dv.setInt32(0, 25, false); // 在第一个字节以大端字节序写入一个值为25的32位整数
复制代码
在引入TypedArray以前,js没有读取或操做二进制数据流的机制。Buffer类是做为nodejs API的一部分引入的,用于在TCP流,文件操做系统,以及上下文中与八位字节流进行交互。
如今可使用 TypedArray
, Buffer
类以更优化和更适合 Node.js 的方式实现了 Uint8Array
API。
buffer类的实例相似于从0到255之间的整数数组(其余整数会经过& 255
操做强制转换到范围内)
初始化较慢,可是能保证新建的buffer实例不包含敏感数据
若是size小于或等于buffer.poolsize的一半,则allocUnsafe生成的buffer实例多是从共享的内部内存池分配,allocUnsafeslow则历来不使用共享的内部内存池
Buffer
实例也是 Uint8Array
实例,可是与 TypedArray
有微小的不一样。(buffer能够类比为视图)
Buffer.from()
与 TypedArray.from()
有着不一样的实现。具体来讲,typedArray.form()可接受第二个参数为映射函数,buffer.form()不行
参考文档: