如何在JavaScript中将ArrayBuffers与数据视图一起使用
我所看到的关于ArrayBuffer的唯一真实教程来自。但我想知道具体如何操作单个字节。例如,来自Mozilla的ArrayBuffers上的这张图片显示了包装在Uint8Array视图中的ArrayBuffers的图像: 它给人的感觉是,你可以用ArrayBuffer来实现这一点:如何在JavaScript中将ArrayBuffers与数据视图一起使用,javascript,bit-manipulation,arraybuffer,typed-arrays,Javascript,Bit Manipulation,Arraybuffer,Typed Arrays,我所看到的关于ArrayBuffer的唯一真实教程来自。但我想知道具体如何操作单个字节。例如,来自Mozilla的ArrayBuffers上的这张图片显示了包装在Uint8Array视图中的ArrayBuffers的图像: 它给人的感觉是,你可以用ArrayBuffer来实现这一点: var x = new ArrayBuffer(10) x[0] = 1 x[1] = 0 ... x[9] = 1 也就是说,手动设置字节。但是我还没有看到任何关于这种特性的文档。相反,您似乎应该要么使用Ty
var x = new ArrayBuffer(10)
x[0] = 1
x[1] = 0
...
x[9] = 1
也就是说,手动设置字节。但是我还没有看到任何关于这种特性的文档。相反,您似乎应该要么使用TypedArray组件,要么使用DataView:
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
console.log(y.getUint32(0)) // 1
console.log(x[0]) // undefined
但是,在使用DataView操作ArrayBuffer之后,您似乎无法直接访问ArrayBuffer上的任何字节
尝试使用ArrayBuffer和DataView进行其他操作时,我感到困惑:
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(1, 2)
console.log(y.getUint32(0)) // 0 (incorrect)
console.log(y.getUint32(1)) // 2 (correct)
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(2, 2)
console.log(y.getUint32(0)) // 0 (incorrect)
console.log(y.getUint32(1)) // 0 (?)
console.log(y.getUint32(2)) // 2 (correct)
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(3, 2)
console.log(y.getUint32(0)) // 0 (incorrect)
console.log(y.getUint32(1)) // 0 (?)
console.log(y.getUint32(2)) // 0 (?)
console.log(y.getUint32(3)) // 2 (correct)
直到最后我得到了与32字节视图一致的4字节。但更奇怪的是:
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(4, 2)
console.log(y.getUint32(0)) // 1
console.log(y.getUint32(1)) // 256
console.log(y.getUint32(2)) // 65536
console.log(y.getUint32(3)) // 16777216
console.log(y.getUint32(4)) // 2
这告诉我需要手动将32位值放置在适当的位置,但我不明白为什么其他值会出现256和65536
接下来,我希望能够打印出1010111100100等字节,整个ArrayBuffer,或者只是其中的一部分
最后,我希望能够对8、16和32位以外的值进行编码,例如base64、4位或奇数位。没有通用的DataView API来实现这一点,比如通用的y.setUint(BitScont,offset,value)
,不知道为什么
总而言之,在处理低级位管理时,有很多我不熟悉的地方。但是,我想学习如何使用它。因此,如果能够快速展示如何获得ArrayBuffer+DataView组合的实用知识,那将非常有帮助
我了解如何使用UINT8阵列和相关类型的Darray,我只是想学习如何使用较低级别的ArrayBuffer。AFAIK
DataView
并不是真正用于您使用它的目的。它基本上用于解析或创建一个已知格式的二进制文件,并处理endian问题。特别是它处理endian问题,并允许您读取未对齐的16位和32位值。换句话说,使用Float32Array
时,缓冲区中的偏移量将是4的倍数,因为32位浮点是4字节。无法在非4字节边界上对齐Float32Array
。使用DataView
传递偏移量,它可以在任何字节边界通过
DataView也被认为比同一API的纯JavaScript实现要慢,至少目前是这样
因此,对于您的用例,您可能不想使用DataView
,而是自己创建
此外,操作随机大小的位字符串不是一种常见的需求,因此如果您想按位读写,您必须编写自己的库
ArrayBuffer
只是一个缓冲区。您不能直接访问其内容。您必须在该缓冲区中创建一个ArrayBufferView
。有许多不同类型的视图,如Int8Array
、Uint32Array
、Float32Array
和DataView
。他们可以查看阵列缓冲区的全部或部分
。他们还可以创建自己的ArrayBuffer
const view = new Uint32Array(100);
它和我的一模一样
const view = new Uint32Array(new ArrayBuffer(400));
您可以通过任何视图的buffer
属性访问该视图的ArrayBuffer
。所以这三条线
const buffer = new ArrayBuffer(400);
const view1 = new Uint32Array(buffer);
const view2 = new Uint8Array(buffer);
与这两行相同
const view1 = new Uint32Array(100);
const view2 = new Uint8Array(view1.buffer);
对于第一个示例,传递到DataView
的偏移量是以字节为单位的,因此
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(1, 2)
console.log(y.getUint32(0)) // 0 (incorrect)
console.log(y.getUint32(1)) // 2 (correct)
第一个y.setUint32(0,1)
设置缓冲区的前4个字节。字节0、1、2和3。第二个y.setUint32(1,2)
设置字节1,2,3,4。所以您正在覆盖字节1、2和3
var x = new ArrayBuffer(100)
// x is 100 bytes `[0, 0, 0, 0, 0, 0, 0 ....`
var y = new DataView(x)
y.setUint32(0, 1); // default is big endian
// x is now [0, 0, 0, 1, 0, 0 ...
y.setUint32(1, 2)
// offset1 --+ (then 4 bytes over written with big endian 2)
// | | | |
// V V V V
// x is now [0, 0, 0, 0, 2, 0, ... BYTES!!!
console.log(y.getUint32(0)) // 0 (incorrect)
// this gets the first 4 bytes as a big endian Uint32 so it's doing
//
// result = x[0] << 24 + x[1] << 16 + x[2] << 8 + x[3]
// 0 << 24 + 0 << 16 + 0 << 8 + 0
// 0
AFAIK
DataView
并不真正适合您使用它的目的。它基本上用于解析或创建一个已知格式的二进制文件,并处理endian问题。特别是它处理endian问题,并允许您读取未对齐的16位和32位值。换句话说,使用Float32Array
时,缓冲区中的偏移量将是4的倍数,因为32位浮点是4字节。无法在非4字节边界上对齐Float32Array
。使用DataView
传递偏移量,它可以在任何字节边界通过
DataView也被认为比同一API的纯JavaScript实现要慢,至少目前是这样
因此,对于您的用例,您可能不想使用DataView
,而是自己创建
此外,操作随机大小的位字符串不是一种常见的需求,因此如果您想按位读写,您必须编写自己的库
ArrayBuffer
只是一个缓冲区。您不能直接访问其内容。您必须在该缓冲区中创建一个ArrayBufferView
。有许多不同类型的视图,如Int8Array
、Uint32Array
、Float32Array
和DataView
。他们可以查看阵列缓冲区的全部或部分
。他们还可以创建自己的ArrayBuffer
const view = new Uint32Array(100);
它和我的一模一样
const view = new Uint32Array(new ArrayBuffer(400));
您可以通过任何视图的buffer
属性访问该视图的ArrayBuffer
。所以这三条线
const buffer = new ArrayBuffer(400);
const view1 = new Uint32Array(buffer);
const view2 = new Uint8Array(buffer);
与这两行相同
const view1 = new Uint32Array(100);
const view2 = new Uint8Array(view1.buffer);
对于第一个示例,传递到DataView
的偏移量是以字节为单位的,因此
var x = new ArrayBuffer(100)
var y = new DataView(x)
y.setUint32(0, 1)
y.setUint32(1, 2)
console.log(y.getUint32(0)) // 0 (incorrect)
console.log(y.getUint32(1)) // 2 (correct)
第一个y.setUint32(0,1)
设置缓冲区的前4个字节。字节0、1、2和3。第二个y.setUint32(1,2)
设置字节1,2,3,4。所以您正在覆盖字节1、2和3
var x = new ArrayBuffer(100)
// x is 100 bytes `[0, 0, 0, 0, 0, 0, 0 ....`
var y = new DataView(x)
y.setUint32(0, 1); // default is big endian
// x is now [0, 0, 0, 1, 0, 0 ...
y.setUint32(1, 2)
// offset1 --+ (then 4 bytes over written with big endian 2)
// | | | |
// V V V V
// x is now [0, 0, 0, 0, 2, 0, ... BYTES!!!
console.log(y.getUint32(0)) // 0 (incorrect)
// this gets the first 4 bytes as a big endian Uint32 so it's doing
//
// result = x[0] << 24 + x[1] << 16 + x[2] << 8 + x[3]
// 0 << 24 + 0 << 16 + 0 << 8 + 0
// 0
它说“你不能直接操纵ArrayBuffer的内容”。这就是为什么你不能做像x[0]=1这样的事情