js二进制数据,文件---ArrayBuffer,二进制数组

1.二进制数据        

        在 JavaScript 中有很多种二进制数据格式,比如:ArrayBufferUint8ArrayDataViewBlobFile 及其他。

2.ArrayBuffer

        基本的二进制对象是 ArrayBuffer —— 对固定长度的连续内存空间的引用ArrayBuffer 是核心对象,是所有的基础,是原始的二进制数据

let buffer = new ArrayBuffer(16);// 分配一个 16 字节的连续内存空间,并用 0 进行预填充。
console.log(buffer);// 内部是空值,仅开辟了空间

要注意的是:

ArrayBuffer 不是某种东西的数组(array 只是形容,表示这个数据是连续的字节流)

让我们先澄清一个可能的误区。ArrayBuffer 与 Array 没有任何共同之处

  • 它的长度是固定的,我们无法增加或减少它的长度。
  • 它正好占用了内存中的那么多空间。
  • 要访问单个字节,需要另一个“视图”对象,而不是 buffer[index]

可以查看打印的结果:

        打印结果包括了一个8位的视图内容(视图是将字节流可视化,让我们能够操作这个字节空间),还有字节流的长度。

        可以看到我们并不能直接对ArrayBuffer进行操作,连打印结果都是转换成视图展示。而真正要对ArrayBuffer进行操作也正是需要视图(view)

3.视图(view)

        操作 ArrayBuffer,我们需要使用“视图”对象。

        视图对象本身并不存储任何东西。它是一副“眼镜”,透过它来解释存储在 ArrayBuffer 中的字节,例如:

  • Uint8Array —— 将 ArrayBuffer 中的每个字节视为 0 到 255 之间的单个数字(每个字节是 8 位,因此只能容纳那么多)。这称为 “8 位无符号整数”。
  • Uint16Array —— 将每 2 个字节视为一个 0 到 65535 之间的整数。这称为 “16 位无符号整数”。
  • Uint32Array —— 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”。
  • Float64Array —— 将每 8 个字节视为一个 5.0x10-324 到 1.8x10308 之间的浮点数。

// 通过视图(view)来对二进制数据操作
let view = new Uint32Array(buffer); // 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”
console.log("视图:",view,"视图存储整数的个数:",view.length,"视图检查的二进制数据流的字节长度:",view.byteLength);// 类数组
view[0] = 1000;
console.log(view,buffer);// 第一个位置存入了100

通过view我们可以直观的看到ArrayBuffer的空间大小和内容,以及存放遍历数据(类数组)

4.TypedArray

        所有这些视图(Uint8ArrayUint32Array 等)的通用术语(总称)是 TypedArray。它们共享同一方法和属性集,以下都属于TypedArray

  • Uint8ArrayUint16ArrayUint32Array —— 用于 8 位、16 位和 32 位无符号整数。
  • Uint8ClampedArray —— 用于 8 位整数,在赋值时便“固定”其值。
  • Int8ArrayInt16ArrayInt32Array —— 用于有符号整数(可以为负数)。
  • Float32ArrayFloat64Array —— 用于 32 位和 64 位的有符号浮点数。

        注意,没有名为 TypedArray 的构造器(以下构造方法只是引用,并没有new TypedArray的构造方法,应该使用new Uint32Array,new Uint8Array),它只是表示 ArrayBuffer 上的视图之一的通用总称术语:Int8ArrayUint8Array 及其他,当你看到 new TypedArray 之类的内容时,它只是代替 new Int8Array(8位整数)new Uint8Array (8位无符号整数)及其他中之一。

类型化数组的行为类似于常规数组:具有索引,并且是可迭代的。

它有5中构造方法

new TypedArray(buffer, [byteOffset], [length]);
new TypedArray(object);
new TypedArray(typedArray);
new TypedArray(length);
new TypedArray();
  1. 如果给定的是 ArrayBuffer 参数,则会在其上创建视图。上面已经用过这个语法了。

        参数1ArrayBuffer,一个二进制数据对象,参数2:可选,给定视图读取的起始位置 (默认为 0),参数3:可选, 视图读取的长度(默认至 buffer 的长度)

let viewT1 = new Uint32Array(buffer,0,2);
console.log(viewT1);

对比默认的参数,这里是从第0位开始读取2位数据。

        2.如果给定的是 Array,或任何类数组对象,则会创建一个相同长度的类型化数组,并复制其内容,我们可以使用它来预填充数组的数据

let viewT2 = new Uint8Array([0,1,2,3]);
console.log(viewT2);

        3.如果给定的是另一个 TypedArray,也是如此:创建一个相同长度的类型化数组,并复制其内容。

let viewT3 = new Uint16Array(viewT1);
console.log(viewT3);

可以看到直接复制了一份viewT1的内容,但是转换了格式(32->16)

4.对于数字参数 length —— 创建指定长度的类型化数组,并用0默认填充内容。

let viewT4 = new Uint8Array(6);
console.log(viewT4);

5.不带参数的情况下,创建长度为零的类型化数组,定义变量类型。

 TypedArray 的属性:

  • view.buffer —— 读取的对应ArrayBuffer
  • view.byteLength —— ArrayBuffer 的长度。
let view = new Uint32Array(buffer); // 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”
console.log("视图:",view,"视图存储整数的个数:",view.length,"视图检查的二进制数据流的字节长度:",view.byteLength,"视图读取的二进制数据流:",view.buffer);// 类数组

越界行为

        当对视图进行转换时,可能出现长度越界,例如,我们尝试将 256 放入 Uint8Array。256 的二进制格式是 100000000(9 位),但 Uint8Array 每个值只有 8 位,最终数字1会被移除,只保留后面的8个0,如果刚好1是符号位,那么就可能会出现正负转换(这就是计算时数据太大,正数加成负数的原因)

256和257最终变成 0和1

TypedArray 的方法:

   TypedArray 具有常规的 Array 方法,但有个明显的例外。我们可以遍历(iterate),mapslicefind 和 reduce 等:

  • arr.set(fromArr, [offset]) 从 offset(默认为 0)开始,将 fromArr 中的所有元素复制到 arr
  • arr.subarray([begin, end]) 创建一个从 begin 到 end(不包括)相同类型的新视图。这类似于 slice 方法(同样也支持),但不复制任何内容 —— 只是创建一个新视图,以对给定片段的数据进行操作。

但有几件事我们做不了:

  • 没有 splice —— 我们无法“删除”一个值,因为类型化数组是缓冲区(buffer)上的视图,缓冲区表示的计算机中的0,1数据,这是硬件决定的,我们不能将硬件删除。我们所能做的就是分配一个零值表示这个数据是空的,只能置零不能删除
  • 无 concat 方法。
// (销毁数据)遍历视图,将二进制数据置零
function delData(view){
    view.map((item,index,array)=>{
        array[index] = 0;
    });
}
delData(view);
console.log(view);

这样就实现了删除数据的效果

5.DataView

        DataView是在 ArrayBuffer 上的一种特殊的超灵活“未类型化”视图。它允许以其他任何格式(8位,16位,32位,等)访问任意长度的数据。

        对于类型化的数组,构造器决定了其格式,只能访问当前格式的数据(8位的数据的数组,只能拿到8位的数据

        通过 DataView,我们可以使用 .getUint8(i) 或 .getUint16(i) 之类的方法访问数据。我们在调用方法时选择格式,而不是在构造的时候。

new DataView(buffer, [byteOffset], [byteLength])
buffer —— 底层的 ArrayBuffer。与类型化数组不同,DataView 不会自行创建缓冲区(buffer)。我们需要事先准备好。
byteOffset —— 视图的读取的起始位置(默认为 0)。
byteLength —— 视图的读取长度(默认至 buffer 的末尾)。

// 4 个字节的二进制数组,每个都是最大值 255,一串都为1的二进制数据
let bufferData = new Uint8Array([255, 255, 255, 255]).buffer;// 通过视图得到二进制数据
console.log(bufferData);

let dataView = new DataView(bufferData);
console.log(dataView.getUint8(0),dataView.getUint16(0),dataView.getUint32(0))
dataView.setUint32(0, 0); // 将 4 个字节的数字设为 0,即将所有字节都设为 0
console.log(dataView.getUint32(0));

        用 DataView 可以轻松访问一个ArrayBuffer 的任意视图格式(8位,16位,32位,等)的内容,这拥有很高的灵活性

6.总结

  ArrayBuffer 是核心对象,是对固定长度的连续内存区域的引用,几乎任何对 ArrayBuffer 的操作,都需要一个视图。它可以是 TypedArray,或者或 DataView

完整代码和结果

let buffer = new ArrayBuffer(16);// 分配一个 16 字节的连续内存空间,并用 0 进行预填充。
console.log(buffer);// 内部是空值,仅开辟了空间
// 通过视图(view)来对二进制数据操作
let view = new Uint32Array(buffer); // 将每 4 个字节视为一个 0 到 4294967295 之间的整数。这称为 “32 位无符号整数”
console.log("视图:",view,"视图存储整数的个数:",view.length,"视图检查的二进制数据流的字节长度:",view.byteLength,"视图读取的二进制数据流:",view.buffer);// 类数组
view[0] = 1000;
console.log(view,buffer);// 第一个位置存入了100

// 视图的构造方法
let viewT1 = new Uint32Array(buffer,0,2);
console.log(viewT1);

let viewT2 = new Uint8Array([0,1,2,3]);
console.log(viewT2);

let viewT3 = new Uint16Array(viewT1);
console.log(viewT3);

let viewT4 = new Uint8Array(6);
console.log(viewT4);

// (销毁数据)遍历视图,将二进制数据置零
function delData(view){
    view.map((item,index,array)=>{
        array[index] = 0;
    });
}
console.log(view);
delData(view);
console.log(view);


console.log("------------");

// 4 个字节的二进制数组,每个都是最大值 255,一串都为1的二进制数据
let bufferData = new Uint8Array([255, 255, 255, 255]).buffer;// 通过视图得到二进制数据
console.log(bufferData);

let dataView = new DataView(bufferData);
console.log(dataView.getUint8(0),dataView.getUint16(0),dataView.getUint32(0))
dataView.setUint32(0, 0); // 将 4 个字节的数字设为 0,即将所有字节都设为 0
console.log(dataView.getUint32(0));

  • 30
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值