DataView 视图

如果一段数据包括多种类型(比如服务器传来的 HTTP 数据),这时除了建立ArrayBuffer对象的复合视图以外,还可以通过DataView视图进行操作。

DataView视图提供更多操作选项,而且支持设定字节序。本来,在设计目的上,ArrayBuffer对象的各种TypedArray视图,是用来向网卡、声卡之类的本机设备传送数据,所以使用本机的字节序就可以了;而DataView视图的设计目的,是用来处理网络设备传来的数据,所以大端字节序或小端字节序是可以自行设定的。

DataView视图本身也是构造函数,接受一个ArrayBuffer对象作为参数,生成视图。

  1. new DataView(ArrayBuffer buffer [, 字节起始位置 [, 长度]]);

下面是一个例子。

  1. const buffer = new ArrayBuffer(24);
  2. const dv = new DataView(buffer);

DataView实例有以下属性,含义与TypedArray实例的同名方法相同。

  • DataView.prototype.buffer:返回对应的 ArrayBuffer 对象
  • DataView.prototype.byteLength:返回占据的内存字节长度
  • DataView.prototype.byteOffset:返回当前视图从对应的 ArrayBuffer 对象的哪个字节开始

DataView实例提供 8 个方法读取内存。

  • getInt8:读取 1 个字节,返回一个 8 位整数。
  • getUint8:读取 1 个字节,返回一个无符号的 8 位整数。
  • getInt16:读取 2 个字节,返回一个 16 位整数。
  • getUint16:读取 2 个字节,返回一个无符号的 16 位整数。
  • getInt32:读取 4 个字节,返回一个 32 位整数。
  • getUint32:读取 4 个字节,返回一个无符号的 32 位整数。
  • getFloat32:读取 4 个字节,返回一个 32 位浮点数。
  • getFloat64:读取 8 个字节,返回一个 64 位浮点数。

这一系列get方法的参数都是一个字节序号(不能是负数,否则会报错),表示从哪个字节开始读取。

  1. const buffer = new ArrayBuffer(24);
  2. const dv = new DataView(buffer);
  3. // 从第1个字节读取一个8位无符号整数
  4. const v1 = dv.getUint8(0);
  5. // 从第2个字节读取一个16位无符号整数
  6. const v2 = dv.getUint16(1);
  7. // 从第4个字节读取一个16位无符号整数
  8. const v3 = dv.getUint16(3);

上面代码读取了ArrayBuffer对象的前 5 个字节,其中有一个 8 位整数和两个十六位整数。

如果一次读取两个或两个以上字节,就必须明确数据的存储方式,到底是小端字节序还是大端字节序。默认情况下,DataViewget方法使用大端字节序解读数据,如果需要使用小端字节序解读,必须在get方法的第二个参数指定true

  1. // 小端字节序
  2. const v1 = dv.getUint16(1, true);
  3. // 大端字节序
  4. const v2 = dv.getUint16(3, false);
  5. // 大端字节序
  6. const v3 = dv.getUint16(3);

DataView 视图提供 8 个方法写入内存。

  • setInt8:写入 1 个字节的 8 位整数。
  • setUint8:写入 1 个字节的 8 位无符号整数。
  • setInt16:写入 2 个字节的 16 位整数。
  • setUint16:写入 2 个字节的 16 位无符号整数。
  • setInt32:写入 4 个字节的 32 位整数。
  • setUint32:写入 4 个字节的 32 位无符号整数。
  • setFloat32:写入 4 个字节的 32 位浮点数。
  • setFloat64:写入 8 个字节的 64 位浮点数。

这一系列set方法,接受两个参数,第一个参数是字节序号,表示从哪个字节开始写入,第二个参数为写入的数据。对于那些写入两个或两个以上字节的方法,需要指定第三个参数,false或者undefined表示使用大端字节序写入,true表示使用小端字节序写入。

  1. // 在第1个字节,以大端字节序写入值为25的32位整数
  2. dv.setInt32(0, 25, false);
  3. // 在第5个字节,以大端字节序写入值为25的32位整数
  4. dv.setInt32(4, 25);
  5. // 在第9个字节,以小端字节序写入值为2.5的32位浮点数
  6. dv.setFloat32(8, 2.5, true);

如果不确定正在使用的计算机的字节序,可以采用下面的判断方式。

  1. const littleEndian = (function() {
  2. const buffer = new ArrayBuffer(2);
  3. new DataView(buffer).setInt16(0, 256, true);
  4. return new Int16Array(buffer)[0] === 256;
  5. })();

如果返回true,就是小端字节序;如果返回false,就是大端字节序。