Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/393.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在JavaScript中将ArrayBuffers与数据视图一起使用_Javascript_Bit Manipulation_Arraybuffer_Typed Arrays - Fatal编程技术网

如何在JavaScript中将ArrayBuffers与数据视图一起使用

如何在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

我所看到的关于ArrayBuffer的唯一真实教程来自。但我想知道具体如何操作单个字节。例如,来自Mozilla的ArrayBuffers上的这张图片显示了包装在Uint8Array视图中的ArrayBuffers的图像:

它给人的感觉是,你可以用ArrayBuffer来实现这一点:

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这样的事情