浅析ArrayBuffer、TypedArray和Buffer

前言

接触node后,少不了会对文件进行操做,因而你可能会遇到如下问题:html

  • 在写请求头时,有一个叫做返回响应数据的类型的属性(responseType),支持一个值"arrayBuffer",那arrayBuffer是什么呢?
  • 在node中处理文件时,常常遇到buffer。好比使用fs.readFile()去读文件时,第一个参数的类型是能够是Buffer,那Buffer是什么呢?
  • 在node的介绍Buffer的官方文档有提到一个很重要的东西TypedArray,那TypedArray又是什么呢?

若是你对这三个问题的答案了然于心,那么接下来的文章能够不用看了。若是有疑问的话,能够往下看,说不定就能帮你解决疑问。java

二进制数组

首先你须要了解一下二进制数组,这对于咱们搞明白上面三个问题很是重要。node

是什么:用于处理二进制数据的类。es6

为何存在:javaScript与显卡通讯的时候,大量的实时的数据交互,用文本格式须要进行格式转化,二进制则省去转化时间。api

和数组的关系:buffer的实例相似与整数数组,可是buffer的大小是固定不变的。数组

二进制数组由三类对象组成:网络

  1. ArrayBuffer对象:表明内存之中的一段二进制数据,自己不能直接操做内存,须要经过“视图”进行操做。“视图”部署了数组接口,这意味着,能够用数组的方法操做内存。
  2. TypedArray视图:共包括 9 种类型的视图,好比Uint8Array(无符号 8 位整数)数组视图, Int16Array(16 位整数)数组视图, Float32Array(32 位浮点数)数组视图等等。
  3. DataView视图:能够自定义复合格式的视图,好比第一个字节是 Uint8(无符号 8 位整数)、第2、三个字节是 Int16(16 位整数)、第四个字节开始是 Float32(32 位浮点数)等等,此外还能够自定义字节序。

一波硬解答:函数

  • ArrayBuffer对象表明原始的二进制数据
  • TypedArray视图用来读写简单类型的二进制数据(ArrayBuffer),DataView视图用来读写复杂类型的二进制数据(ArrayBuffer)。
  • Node中的Buffer类是以更优化和更适合Nodejs的方式实现了Unit8Array API,意思就是Buffer类实际上是TypedArray(Unit8Array)的nodejs实现。

至此,上面三个问题应该都解决了。想了解更多的能够继续往下看。优化

ArrayBuffer

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

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 浮点数
可接受的参数
  • 视图的构造函数接受三个参数,第一个ArrayBuffer对象,第二个视图开始的字节号(默认0),第三个视图结束的字节号(默认直到本段内存区域结束)
  • 接受ArrayBuffer实例做为参数,以指定格式读出二进制数据
  • 可接受普通数组做为参数,直接分配内存生成ArrayBuffer实例,并同时对这段内存进行赋值,再根据这段内存生成视图。
  • 可接受视图作为参数,生成的新数组复制了参数视图的值,生成新的数组和视图。(想基于同一内存生成新视图,须要传入视图.buffer)
和数组的区别
  • TypedArray内的成员只能是同一类型
  • TypedArray成员是连续的,不会有空位
  • TypedArray成员的默认值为0,数组的默认值为空
  • TypedArray只是视图,自己不存储数据,数据都存储在底层的ArrayBuffer中,要获取底层对象必须使用buffer属性
  • TypedArray能够直接操做内存,不须要进行类型转换,因此比数组快
  • TypedArray数组有的方法均可以使用,但不能使用cancat方法

DataView

若是一段数据包含多种类型的数据,除了使用复合视图的方式读取以外,还可使用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位整数
    复制代码

Node中的Buffer

在引入TypedArray以前,js没有读取或操做二进制数据流的机制。Buffer类是做为nodejs API的一部分引入的,用于在TCP流,文件操做系统,以及上下文中与八位字节流进行交互。

如今可使用 TypedArrayBuffer 类以更优化和更适合 Node.js 的方式实现了 Uint8Array API。

buffer类的实例相似于从0到255之间的整数数组(其余整数会经过& 255操做强制转换到范围内)

buffer.from()

  • buffer.from(array),返回包含给定八位字节数组的副本的新buffer
  • buffer.from(buffer),返回包含给定buffer副本的新buffer
  • buffer.from(arrayBuffer[, betyOffset[, len]]),返回与给定arrayBuffer共享同一段内存的新Buffer
  • buffer.from(string),返回包含给定字符串副本的新Buffer
  • buffer.alloc(size),返回一个指定大小的新建的已经初始化的Buffer
  • buffer.allocUnsafe(size)/buffer.allocUnsafeslow(size),返回一个指定大小的新建的未初始化(没有被清零)的buffer

初始化较慢,可是能保证新建的buffer实例不包含敏感数据

若是size小于或等于buffer.poolsize的一半,则allocUnsafe生成的buffer实例多是从共享的内部内存池分配,allocUnsafeslow则历来不使用共享的内部内存池

buffer与typedArray

  • Buffer 实例也是 Uint8Array 实例,可是与 TypedArray 有微小的不一样。(buffer能够类比为视图)

  • Buffer.from()TypedArray.from() 有着不一样的实现。具体来讲,typedArray.form()可接受第二个参数为映射函数,buffer.form()不行

参考文档:

ECMAScript入门--ArrayBuffer

Node.js中文网--Buffer

相关文章
相关标签/搜索