zoukankan      html  css  js  c++  java
  • ArrayBuffer、TypedArray、DataView二进制数组

    三个是处理二进制数据的接口。都是类数组。

    1.ArrayBuffer是什么?

    ArrayBuffer是一个二进制对象(文件,图片等)。它指向固定长度的,连续的内存区域。

    const buffer = new ArrayBuffer(16);
    // buffer.byteLength === 16 生成16位字节的二进制数据,每一位都默认是0

    上面分配了一个长度为16个字节的内存区域,代表16byte的二进制数据。并且默认每bit内容都是0。

    1.特点

    1)和数组不同,它创建后长度就固定了,不能增删。

    2)它实实在在占用了内存那么多空间。

    3)不能直接访问里面的数据,需要通过另外的类型数组对象(TypedArray类型)来访问。

    2. 属性

    1.byteLength 

    获取分配的内存区域buffer的字节长度。

    2.slice(start, end)--实例方法

    ArrayBuffer对象唯一一个可以操作内存的方法。

            const buffer = new ArrayBuffer(12);
            const view = new Uint8Array(buffer);
            view[0] = 1; // [1,0,0,....0]
            const newBuffer = buffer.slice(0,3); // [0,3)
            const newView = new Uint8Array(newBuffer);
            console.log(newView); //[1,0,0]

    1)先分配一段新内存,脱离原来的内存

    2)将原来内存中和这段新内存对应的部分的buffer内容拷贝过来

    3.isView(param)---静态方法

    判断参数是否为该ArrayBuffer的视图实例。

            const buffer = new ArrayBuffer(12);
            const view = new Uint8Array(buffer);
            console.log(ArrayBuffer.isView(view)); // true

    3.字节序 

    ArrayBuffer中的字节存储顺序,是按照小端字节序(little endian);意思是重要字节顺序往后排。

    ⚠️重要字节意思是:权重越大越重要,百位比十位重要,十位比各位重要

    与之相对应的是大端字节序(big endian);意思是重要的字节顺序排前面。

    例如:

            const view32 = new Uint32Array([1,1000]);
            const view16 = new Uint16Array(view32.buffer);
            console.log(view32); // [1,1000]
            // [1,1000]都是32位的四字节
            // 1--转16位相当于前16位0, 后16位1
            // 1000--转16位相当于前16位0, 后16位1000
            console.log(view16) // [1,0,1000,0]

    ps:判断字节序的方法

    const BIG_ENDIAN = Symbol('BIG_ENDIAN');
    const LITTLE_ENDIAN = Symbol('LITTLE_ENDIAN');
    
    function getPlatformEndianness() {
      let arr32 = Uint32Array.of(0x12345678);
      let arr8 = new Uint8Array(arr32.buffer);
      switch ((arr8[0]*0x1000000) + (arr8[1]*0x10000) + (arr8[2]*0x100) + (arr8[3])) {
        case 0x12345678:
          return BIG_ENDIAN;
        case 0x78563412:
          return LITTLE_ENDIAN;
        default:
          throw new Error('Unknown endianness');
      }
    }

    4.buffer和字符串互相转化

    /**
     * Convert ArrayBuffer/TypedArray to String via TextDecoder
     *
     * @see https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder
     */
    function ab2str(
      input: ArrayBuffer | Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array,
      outputEncoding: string = 'utf8',
    ): string {
      const decoder = new TextDecoder(outputEncoding)
      return decoder.decode(input)
    }
    
    /**
     * Convert String to ArrayBuffer via TextEncoder
     *
     * @see https://developer.mozilla.org/zh-CN/docs/Web/API/TextEncoder
     */
    function str2ab(input: string): ArrayBuffer {
      const view = str2Uint8Array(input)
      return view.buffer
    }
    
    /** Convert String to Uint8Array */
    function str2Uint8Array(input: string): Uint8Array {
      const encoder = new TextEncoder()
      const view = encoder.encode(input)
      return view
    }

    2.视图类对象:

    视图对象自己本身不存储任何东西。它是一个访问内存中数据的工具。同一段内存,不同的访问会得到不同的数据。

    类型数组对象可以分为两种,一种是TypedArray,一种是DataView

    1.TypedArray类型数组对象

    它是一个统称,不是具体的对象。它创建后的数值的类型就固定了。

    1. 分类如下:

    • Uint8Array, Uint16Array, Uint32Array---分别是8位,16位,32位的无符号整数。
    • Uint8ClampedArray:---8位整数,但是溢出时处理逻辑不同。(超出255的全部按255,低于0的全部按0,适用于处理图像)
    • Int8Array,Int16Array,Int32Array---8位,16位,32位有符号整数。可能是负数。
    • Float32Array, Float64Array---32位,64位的浮点数。

    其中对于第一类简单解释如下:

    1. Uint8Array将内存中的每个字节当成一个整数,值大小范围为0-255;
    2. Uint16Array将内存中每两个字节当成一个整数,值范围大小为0-65535;
    3. Uint32Array将内存中每四个字节当成一个整数,值范围大小为0-4294967295;

    PS 溢出规则

    正向溢出(overflow):当输入值大于当前数据类型的最大值,结果等于当前数据类型的最小值加上余值,再减去 1。
    负向溢出(underflow):当输入值小于当前数据类型的最小值,结果等于当前数据类型的最大值减去余值的绝对值,再加上 1。

    2.类型数组对象的用法如下:

    如果不传入buffer,会自动创建ArrayBuffer,然后通过TypedArray的buffer属性访问。因为类型数组对象依赖ArrayBuffer存在,否则毫无意义。

    1. new TypedArray(buffer, [byteoffset], [length])

     其中buffer为传入的内存空间; byteoffset默认是0,为查看内存视图的开始位置; length为查看的长度,默认到最后一个元素。

      ⚠️如果是Uint16Array,byteoffset必须是2的倍数,同理Uint32Array的必须是4的倍数    

          如果想任意位置开始,可以使用DataView

            const buffer = new ArrayBuffer(16);
            console.log(buffer.byteLength); // 分配内存的大小 16
            // 下面表示从索引2开始取5个整数的长度
            const view16 = new Uint16Array(buffer,2,5);
            console.log(view16.length); // 数字的长度

    2. new TypedArray(object); --传入数组或者类数组.

            const view8 = new Uint8Array([1,2,3,4]); // 分配一个新的内存,不同于原来的数组的内存
            const view8Buffer = view8.buffer;
            console.log(view8.length); // 4
            console.log(view8Buffer.byteLength); // 4
           // 因为类数组,可以[...view8]还原成数组

    3.new TypedArray(typedArray)--将类型数组对象当参数传入

            const view16 = new Uint16Array([1,1000]); // 创建一个和数组同长度的视图数组
            const view8 = new Uint8Array(view16); // view8创建一个同样长度的视图数组,并将值copy过来
            console.log(view8[0]); // 1
            console.log(view8[1]); // 232
            // 1000大于255,需要对溢出的值进行截取; 
            // (1000).toString(2) === "1111101000"
            // view8只能取最右侧8位,parseInt(11101000, 2) === 232
    
            // 另外,上面view8,view16操作 。,,的底层buffer是两个,因为不传入buffer,就会自动创建buffer
            // 如果想要操作一个buffer, 需要将buffer传入
            const newView8 = new Uint8Array(view16.buffer);
            view16[0] = 123;
            console.log(view16.buffer);
            console.log(view16); // [123,1000]
            console.log(newView8); // [123, 0, 232, 3]
            console.log(view8[0]); // 1
            console.log(newView8[0]); // 123

    4. new TypedArray(length)--创建一个length长度的类型数组

            const view16 = new Uint16Array(4);
            const viewBuffer = view16.buffer;
            console.log(view16.length); // 4
            console.log(viewBuffer.byteLength); // 4*2=8
            console.log(view16[0]); // 0

    5. new TypedArray() --创建一个长度为0的类型数组

    3.属性

    • BYTES_PER_ELEMENT: 每个数据所占的字节数
            const view16 = new Uint16Array(view32.buffer);
            console.log(view16.BYTES_PER_ELEMENT);  //2
    • buffer: 返回视图对应的ArrayBuffer对象
    • byteLength: 字节的长度
    • length是数据的长度
    • byteOffset:从buffer读取数据的开始位置

    4.方法

    可以使用数组的查询遍历类方法:如map,slice, find, reduce等;

    不可以使用数组的方法: 如splice, concat;

    除此之外还有:

    • arr.set(formArr, [offset])--代替实现原来的concat方法。

          将fromArr的值写入,从arr的offset开始写入

            const view16 = new Uint16Array(10);
            const view8 = new Uint8Array([1,2,3,4]);
            view16.set(view8,2); // 表示从view16的索引为2开始,把view8的内容复写到view16中
            // 所以view8的长度+length必须不大于view16的长度
            console.log(view16); // [0,0,1,2,3,4,0,0,0,0];
    • arr.subarray([begin, end])--创建一个新的视图,值是原来数组截取的部分值;

      类似slice()[begin, end)

            console.log(view16); // [0,0,1,2,3,4,0,0,0,0];
            const newView = view16.subarray(3,4)
            console.log(newView); // [2]
    • of()---静态方法

    Uint8Array.of(1,2,3)
    // 相当于
    new Uint8Array([1,2,3])
    • from(arr, [fun])---静态方法
    // 1.转为实例
    Uint8Array.from([1,3])
    // 2. 使用第二个参数方法
    Int8Array.of(127, 126, 125).map(x => 2 * x)
    // Int8Array [ -2, -4, -6 ]
    
    Int16Array.from(Int8Array.of(127, 126, 125), x => 2 * x)
    // Int16Array [ 254, 252, 250 ]

    2.DataView对象

    1.基础信息

    是一个超级灵活和“无类型”的视图。它允许以任意offset(偏移量)访问任意类型的数组。

    也可以自定义复合类型的视图。可以自定义字节序(处理网络设备传递的数据,可能是大字节序)。

    不同于TypedArray的构造函数调用就决定了数据类型,DataView是调用方法的时候决定数据类型,如.getUint8(i)等;

    支持8种数据存取,除了Uint8ClampsArray不支持,其他TypedArray的的类型都支持

    new DataView(buffer, [byteoffset], [bytelength])

    不同于TypedArray可以自行创建buffer, DataView要求必须传入buffer。

            const buffer = (new Uint8Array([255,255,253,252])).buffer;
            const dataView = new DataView(buffer);
            console.log(dataView.getUint8(0)); // 255
            console.log(dataView.getUint16(0)); // 65535
            dataView.setUint32(0,0);
            console.log(dataView.getUint32(0)); // 0

    2. 属性

    • buffer
    • byteLength
    • byteOffset

    3.方法

    get方法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 位浮点数。

    set方法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方法可以传递第三个参数,true表示小端字节序写入;false表示大端字节序写入。

    // 判断当前计算机的字节序
    const littleEndian = (function() {
      const buffer = new ArrayBuffer(2);
      new DataView(buffer).setInt16(0, 256, true);
      return new Int16Array(buffer)[0] === 256;
    })(); // true表示小端

    3. 应用

          

  • 相关阅读:
    基于Metaweblog API 接口一键发布到国内外主流博客平台
    uva144 Student Grants
    Uva 10452
    Uva 439 Knight Moves
    Uva 352 The Seasonal War
    switch语句
    java——基础知识
    我的lua学习2
    codeforces 431 D. Random Task 组合数学
    codeforces 285 D. Permutation Sum 状压 dfs打表
  • 原文地址:https://www.cnblogs.com/lyraLee/p/11595255.html
Copyright © 2011-2022 走看看