zoukankan      html  css  js  c++  java
  • js 的 ArrayBuffer 和 dataView

    一个十六进制代表4位,0xF = 1111,0xFF = 1111 1111,八位是1字节,所以通常用两个16进制代表1字节。

    假如我申请一个8字节的内存空间,然后初始化为0,大概就这样: 00 00 00 00 00 00 00 00

    什么是类型,BYTE(1字节),WORD(2字节),DWORD(4字节),QWORD(8字节) 这种类型是在读/写内存地址时的偏移字节数,当然也可以手动偏移

    arrayBuffer 中的Int8是8位也就是BYTE类型,对它进行读写的偏移值是1字节
    arrayBuffer 中的Int16是16位也就是WORD类型,对它进行读写的偏移值是2字节

    假如我申请一块4字节大小的空间,并按4字节大小进行读取:

    let buffer = new ArrayBuffer(4)
    let view = new Uint32Array(buffer);
    view[0] = 0xA
    

    如果这时候打印buffe将会看到如下结构:

    ArrayBuffer(4) {}
    [[Int8Array]]: Int8Array(4) [10, 0, 0, 0]
    [[Int16Array]]: Int16Array(2) [10, 0]
    [[Int32Array]]: Int32Array [10]
    [[Uint8Array]]: Uint8Array(4) [10, 0, 0, 0]
    byteLength: 4
    

    Int32Array显示为0x0000 000A,Int8Array显示为0x0A00 0000,为什么Int8Array显示为0x0A00 0000而不是0x0000 000A。

    这可能是因为我的计算机是以小端模式存储数据,什么是小端模式:数据低位在地址低位,数据高位在地址高位

    假如我在0x100-0x200的虚拟内存空间中申请一块4字节内存,返回的内存地址(在有“指针”的计算机语言中也叫做“指针”)为0x180,
    这时将0x0000 000A存进去,数据的高位时在左边,低位在右边0A这里, 在0x180地址存就像:

    0x17D 0A
    0x17E 00
    0x17F 00
    0x180 00
    

    如果这个时候再用Int8Array操作一下这段内存数据:

    let view2 = new Int8Array(buffer)
    view2[1] = 0x01 // 0A 01 00 00
    

    这时的内存数据为 0A 01 00 00,也就是0x010A十进制的266,这时再用view查看4字节数据也是266

    ArrayBuffer 所有的数据都是10进制显示的

    ArrayBuffer 不能直接操作,而是要通过类型数组对象DataView 对象来操作, 它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

    上面是基础计算机内存知识,下面时ArrayBuffer api知识

    let l = console.log
    
    // 申请一个大小为8字节的内存空间,初始化为0
    let buffer = new ArrayBuffer(8) 
    l(buffer.byteLength) // 单位为字节
    
    // 查看是否是ArrayBuffer
    l( ArrayBuffer.isView(new DataView(buffer)) )
    
    
    // 使用一个 Int32Array 来引用
    // 32 代表32位,4字节。buffer申请的空间只有8字节,只能存两个int32的值
    let view = new Int32Array(buffer) 
    l(view)
    
    // 4字节最大就只能存 0x00000000 - 0xFFFFFFFF
    view[0] = 0xFFFF
    view[1] = 0xFFFE
    

    byteLength 和 length

    byteLength不会变化(字节大小), length会更具 类型数组对象 发生变化

    let l = console.log
    let buffer = new ArrayBuffer(8)
    
    let int8 = new Int8Array(buffer)
    l(int8.byteLength, int8.length) // 8, 8
    let uint8 = new Uint8Array(buffer)
    l(uint8.byteLength, uint8.length) // 8, 8
    let uint8clamped = new Uint8ClampedArray(buffer)
    l(uint8clamped.byteLength, uint8clamped.length)// 8, 8
    
    let int16 = new Int16Array(buffer)
    l(int16.byteLength, int16.length) // 8, 4 小两倍
    let uint16 = new Uint16Array(buffer)
    l(uint16.byteLength, uint16.length)// 8, 4
    
    let int32 = new Int32Array(buffer)
    l(int32.byteLength, int32.length)// 8, 2 小四倍
    let uint32 = new Uint32Array(buffer)
    l(uint32.byteLength, uint32.length)// 8, 2
    

    类型数组对象 文档

    new TypedArray(length); 常用
    > 当传入length参数时,一个内部数组缓冲区被创建.
    > 该缓存区的大小是传入的length乘以数组中每个元素的字节数,每个元素的值都为0.
    > (译者注:每个元素的字节数是由具体的构造函数决定的,比如Int16Array的每个元素的字节数为2,Int32Array的每个元素的字节数为4)
    
    new TypedArray(typedArray); 常用
    new TypedArray(object); 
    new TypedArray(buffer [, byteOffset [, length]]); 常用
    
    以下皆是 TypedArray() : 
    Unsigned Int 无符号整数
    
    Int8Array(); 
    Uint8Array(); 
    
    Uint8ClampedArray();
    
    Int16Array(); 
    Uint16Array();
    
    Int32Array(); 
    Uint32Array(); 
    
    Float32Array(); 
    Float64Array();
    
    
    
    let l = console.log
    let buffer = new ArrayBuffer(8)
    let a = new Int8Array(buffer)
    for (let i = 0; i < buffer.byteLength; i++) {
    	a[i] = i
    }
    l(a) // Int8Array(8) [0, 1, 2, 3, 4, 5, 6, 7]
    l(a[a.byteLength - 1]) // 使用下标获取值
    l(a.length) // 实际长度
    
    l(new Int8Array(buffer, 2)) // 偏移两位 Int8Array(6) [2, 3, 4, 5, 6, 7]
    

    DataView 文档

    DataView 视图是一个可以从 ArrayBuffer 对象中读写多种数值类型的底层接口,在读写时不用考虑平台字节序问题(默认大端法)

    如果由偏移(byteOffset)和字节长度(byteLength)计算得到的结束位置超出了 buffer 的长度,抛出此异常。

    let l = console.log
    // new DataView(buffer [, byteOffset [, byteLength]])
    let buffer = new ArrayBuffer(8)
    let view = new DataView(buffer, 0)
    
    // setInt16(byteOffset: number, value: number, littleEndian?: boolean)
    // 如果littleEndian为true则按小端法存储,否则就按大端法存储, 默认是大端
    view.setInt16(0, 14)
    l(view)
    
    // getInt16(byteOffset: number, littleEndian?: boolean)
    l(view.getInt16(0))// 14
    l(view.getInt8(0))// 0
    l(view.getInt32(0))// 917504
    
    // 只读属性,实例的时候已固化
    l(view.buffer)
    l(view.byteLength)
    l(view.byteOffset)
    

    字节序

    let l = console.log
    var littleEndian = (function () {
    	var buffer = new ArrayBuffer(2);
    	// 小端字节序和大端字节序: https://blog.csdn.net/qq_33724710/article/details/51056542
    	new DataView(buffer).setInt16(0, 256, true /* 设置值时使用小端字节序 */ );
    	// Int16Array 使用系统字节序,由此可以判断系统是否是小端字节序
    
    	l(buffer)
    	let int16 = new Int16Array(buffer)
    	l(int16)
    	return int16[0] === 256;
    })();
    console.log(littleEndian); // true or false
    

    buffer库,和nodejs的Buffer基本一样的api

    <script src="https://bundle.run/buffer@5.6.0"></script>
    <script>
      const { Buffer } = buffer;
      const buf = Buffer.alloc(4);
      buf.writeInt32LE(0x0A);
      console.log(buf);
      console.log(buf.readInt32LE().toString(16) );
    </script>
    
  • 相关阅读:
    python_Opencv_使用Matplotlib模块
    django中同源策略和跨域解决方案
    ES6常用语法
    django之页面缓存
    django组件之ContentType
    我的博客园设置
    rest_framework 之版本控制
    rest_framework 之分页器
    在django项目中手动模拟实现settings的配置
    rest_framework之url控制器详解
  • 原文地址:https://www.cnblogs.com/ajanuw/p/9248508.html
Copyright © 2011-2022 走看看