使用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
},