使用ArrayBuffer对象保存二进制数据,使用TypedArray和DataView 视图来读写数据。
const buff = new ArrayBuffer(4)
这样就创建了一个4(byte)字节的长度的内存判断,初始值都为0
注:一般中文占2个字节,英文占1个字节。不同的编码会不同比如:中文在UTF-8占3个字节、在UTF-16中占4个字节
buff.byteLength
// 4
buff.slice(1,3)
// ArrayBuffer(2)
// 拷贝了 buff 里下标 1、2 的内存数据
如:
Uint8是8位不带符号整数,值范围是 0 到 255 ,长度为1Byte
而 Int32 是有符号整数,值范围是 -2,147,483,648
到 +2,147,483,647
,长度为 4 Byte。
ArrayBuffer
支持使用以下 9 种类型来读写内存数据:
Int8
8位带符号整数 signed char
Uint8
8位不带符号整数 unsigned char
Uint8C
8位不带符号整数(自动过滤溢出) unsigned char
Int16
16位带符号整数 short
Uint16
16位不带符号整数 unsigned short
Int32
32位带符号整数 int
Uint32
32位不带符号的整数 unsigned int
Float32
32位浮点数 float
Float64
64位浮点数 double
TypedArray
可以将一段 ArrayBuffer
的数据全部使用我们设定的类型来操作。
TypedArray
可以使用 9 种类型,每个类型有对应的构造函数:
构造函数接收一个 ArrayBuffer
对象,将其转换成指定类型的二进制数组。
new (array: ArrayBufferLike | ArrayLike<number>, byteOffset?: number | undefined, byteLength?: number | undefined) => TypedArray
同一个 ArrayBuffer
可以生成多个不同类型的 TypedArray
。
const buff = new ArrayBuffer(4)
// 申请了长度为 4 字节的内存
const uInt8 = new Uint8Array(buff)
// 创建了长度为 4 的数组 (因为 Uint8 的单位长度是 1 字节)
const int32 = new Int32Array(buff)
// 创建了长度为 1 的数组(因为 Int32Array 的单位长度是 4 字节)
// 如果有需要,也可以设定起始位置的偏移量,以及从起始位置开始的内存长度
const uInt8 = new Uint8Array(buff, 1, 2)
TypedArray 是类数组对象,我们可以使用数组的方式来操作,如:
// 读
uInt8[0]
// 写
uInt8[0] = 1
// 数组方法
uInt8.findIndex(val=>val===0)
注意:
使用 ArrayBuffer
数据创建 TypedArray
时,生成的 TypedArray
对象数组只是对 ArrayBuffer
的引用。
buffer
:保存着这个 TypedArray
操作的 ArrayBuffer
对象。所以从 TypedArray
对象里返回其数据时,要使用它的 buffer
属性。byteOffset
:起始位置的偏移量byteLength
:字节长度,也就是内存使用量。length
:数组长度,根据类型不同,数组长度也不同。例如 4 字节的 byteLength
,以 Uint8Array 读取则 length
为 4,以 Int32Array 读取则 length
为 1。
DataView
和 TypedArray
有一些区别:
TypedArray
把整个 ArrayBuffer
全部视为某种指定的类型,而 DataView
每次操作都必须手动指明类型,所以它可以灵活使用多种类型。TypedArray
是类数组对象,但 DataView
不是类数组对象,所以不能使用数组的方法。TypedArray
不能设定字节序(总是小端),而 DataView
可以设定字节序(大端或小端)(默认小端)。使用 DataView
构造函数来创建一个 DataView
对象。
语法:
new (buffer: ArrayBufferLike, byteOffset?: number | undefined, byteLength?: number | undefined) => DataView
简单示例:
const view = new DataView(buff)
// 如果有需要,也可以设定起始位置的偏移量,以及从起始位置开始的内存长度
const view = new DataView(buff, 2, 2)
由于创建 DataView
对象时不能指定类型,所以我们在操作时必须手动指定类型。
DataView
只有对内存的读、写操作,而且要使用指定的方法。它不能像 TypedArray
那样使用数组下标和数组方法。
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 位浮点数。const view = new DataView(buff)
view.getUint8(0)
view.getUint16(1)
// DataView.getUint16(byteOffset: number, littleEndian?: boolean | undefined): number
// 使用大端字节序
view.getUint32(2, false)
第一个参数是读取的内存的位置;
第二个参数是可选参数,用来指定字节序。只有当一次性读取超过 1 字节时才有这个参数。
DataView
默认使用小端字节序。如果你要使用大端字节序,必须把第二个参数设置为 false
。
DataView
写内存的方法也是 8 个,与读内存的 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 位浮点数。const view = new DataView(buff)
// DataView.setInt8(byteOffset: number, value: number): void
view.setInt8(0, 0xbb)
// DataView.setInt16(byteOffset: number, value: number, littleEndian?: boolean | undefined): void
view.setInt16(4, 1, true)
view.setInt32(8, 520, true)
buffer
:保存着这个 DataView
操作的 ArrayBuffer
对象。所以从 DataView
对象里返回其数据时,要使用它的 buffer
属性。byteOffset
:起始位置的偏移量byteLength
:字节长度,也就是内存使用量。DataView
不是类数组对象,所以没有 length
属性。
一些应用方法:
// ArrayBuffer转16进度字符串示例
ab2hex(buffer) {
const hexArr = Array.prototype.map.call(
new Uint8Array(buffer),
function(bit) {
return ('00' + bit.toString(16)).slice(-2)
}
)
return hexArr.join('')
},
// 16进制字符串转ArrayBuffer
hex2ArrayBuffer(hex_str) {
let typedArray = new Uint8Array(hex_str.match(/[\da-f]{2}/gi).map(function(h) {
return parseInt(h, 16)
}))
let buffer = typedArray.buffer
return buffer
},