使用ArrayBuffer对象保存二进制数据,使用TypedArray和DataView 视图来读写数据。
ArrayBuffer代码内存中的一段数据
const buff = new ArrayBuffer(4)
这样就创建了一个4(byte)字节的长度的内存判断,初始值都为0
注:一般中文占2个字节,英文占1个字节。不同的编码会不同比如:中文在UTF-8占3个字节、在UTF-16中占4个字节
ArrayBuffer属性和方法
一个属性:byteLength,获取他里面数据的字节数和
buff.byteLength
// 4
一个方法:slice,和数组slice一个用于拷贝一段内存
buff.slice(1,3)
// ArrayBuffer(2)
// 拷贝了 buff 里下标 1、2 的内存数据
ArrayBuffer不能直接读写,只是放数据的容器,不能直接对内存数据进行读写,因为操作二进制数据可以有多种不同的数据类型、他们字节长度、值范围都不相同,不指定类型,不能读写内存数据
如:
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
TypedArray
可以将一段 ArrayBuffer
的数据全部使用我们设定的类型来操作。
创建 TypedArray
TypedArray
可以使用 9 种类型,每个类型有对应的构造函数:
• Int8Array:8位有符号整数,长度1个字节。
• Uint8Array:8位无符号整数,长度1个字节。
• Uint8ClampedArray:8位无符号整数,长度1个字节,溢出处理不同。
• Int16Array:16位有符号整数,长度2个字节。
• Uint16Array:16位无符号整数,长度2个字节。
• Int32Array:32位有符号整数,长度4个字节。
• Uint32Array:32位无符号整数,长度4个字节。
• Float32Array:32位浮点数,长度4个字节。
• Float64Array:64位浮点数,长度8个字节。
构造函数接收一个 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
TypedArray 是类数组对象,我们可以使用数组的方式来操作,如:
// 读
uInt8[0]
// 写
uInt8[0] = 1
// 数组方法
uInt8.findIndex(val=>val===0)
注意:
使用 ArrayBuffer
数据创建 TypedArray
时,生成的 TypedArray
对象数组只是对 ArrayBuffer
的引用。
TypedArray 的属性
-
buffer
:保存着这个TypedArray
操作的ArrayBuffer
对象。所以从TypedArray
对象里返回其数据时,要使用它的buffer
属性。 -
byteOffset
:起始位置的偏移量 -
byteLength
:字节长度,也就是内存使用量。 -
length
:数组长度,根据类型不同,数组长度也不同。
例如 4 字节的 byteLength
,以 Uint8Array 读取则 length
为 4,以 Int32Array 读取则 length
为 1。
DataView
DataView 和 TypedArray 的区别
DataView
和 TypedArray
有一些区别:
-
TypedArray
把整个ArrayBuffer
全部视为某种指定的类型,而DataView
每次操作都必须手动指明类型,所以它可以灵活使用多种类型。 -
TypedArray
是类数组对象,但DataView
不是类数组对象,所以不能使用数组的方法。 -
TypedArray
不能设定字节序(总是小端),而DataView
可以设定字节序(大端或小端)(默认小端)。
创建 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 读内存
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 写内存
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)
DataView 的属性
-
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
},