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. 应用

          

  • 相关阅读:
    SetWindowsHookEx详解
    C#使用全局钩子(hook),SetWindowsHookEx返回0、不回调的解决
    C#使用全局钩子(hook),SetWindowsHookEx返回0、不回调的解决
    how to get geometry type of layer using IMapServer3 and IMapLayerInfo? (C#)
    how to get geometry type of layer using IMapServer3 and IMapLayerInfo? (C#)
    windows cmd命令显示UTF8设置
    windows cmd命令显示UTF8设置
    C#写的NoSQL开源项目/系统(系列)
    TCP协议详解(2)
    红黑树
  • 原文地址:https://www.cnblogs.com/lyraLee/p/11595255.html
Copyright © 2011-2022 走看看