Lan*_*ard 2 javascript bit-manipulation typed-arrays arraybuffer
我见过的关于 ArrayBuffer 的唯一真正的教程来自HTML5Rocks。但我特别想知道如何操作单个字节。例如,Mozilla 的 ArrayBuffers 上的这个卡通显示了一个包裹在 Uint8Array 视图中的 ArrayBuffer 的图像:
它给人的感觉是你可以用 ArrayBuffer 做到这一点:
var x = new ArrayBuffer(10)
x[0] = 1
x[1] = 0
...
x[9] = 1
Run Code Online (Sandbox Code Playgroud)
即手动设置字节。但是我还没有看到任何关于这种功能的文档。相反,您似乎应该使用 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
Run Code Online (Sandbox Code Playgroud)
但是,在使用 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)
Run Code Online (Sandbox Code Playgroud)
直到最后我得到与 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
Run Code Online (Sandbox Code Playgroud)
这告诉我我需要手动将 32 位值放在适当的位置,但我不明白为什么其他值会像 256 和 65536 一样出现。
接下来,我希望能够将字节打印为 101011100100 等、整个 ArrayBuffer 或其中的一部分。
最后,我希望能够对 8、16 和 32 位以外的值进行编码,例如 base64、4 位或奇数位。没有通用的 DataView API 可以做到这一点,例如 generic y.setUint(bitsCount, offset, value)
,不知道为什么。
总而言之,在处理低级位管理时,有很多我不熟悉的地方。但是,我想学习如何使用它。因此,也许如果可以快速展示如何获得 ArrayBuffer + DataView 组合的工作知识,那将非常有帮助。
我了解如何使用 Uint8Array 和相关的 TypedArrays,我只是想学习如何使用较低级别的 ArrayBuffer。
AFAIKDataView
并不真正适用于您使用它的目的。它基本上用于解析或创建已知格式的二进制文件并处理字节序问题。特别是它处理字节序问题,并且它允许您读取未对齐的 16 位和 32 位值。换句话说,Float32Array
由于 32 位浮点数为 4 个字节,因此缓冲区中的偏移量将是 4 的倍数。无法Float32Array
在非 4 字节边界上对齐 a 。随着DataView
您传入偏移量,它可以在任何字节边界处通过。
DataView 也比相同 API 的纯 JavaScript 实现慢,至少目前是这样。
因此,对于您的用例,您可能不想使用DataView
,而是自己制作。
此外,操作随机大小的位串并不是很常见的需求,因此如果您想按位读取和写入,您将不得不编写自己的库。
ArrayBuffer
只是一个缓冲区。您无法直接访问其内容。您必须在ArrayBufferView
该缓冲区中创建一个。有很多不同类型的意见,像Int8Array
,Uint32Array
,Float32Array
和DataView
。他们可以查看全部或部分ArrayBuffer
. 他们也可以创建自己的ArrayBuffer
.
const view = new Uint32Array(100);
Run Code Online (Sandbox Code Playgroud)
完全一样
const view = new Uint32Array(new ArrayBuffer(400));
Run Code Online (Sandbox Code Playgroud)
您可以ArrayBuffer
通过它的buffer
属性访问任何视图的。所以这3行
const buffer = new ArrayBuffer(400);
const view1 = new Uint32Array(buffer);
const view2 = new Uint8Array(buffer);
Run Code Online (Sandbox Code Playgroud)
与这两行相同
const view1 = new Uint32Array(100);
const view2 = new Uint8Array(view1.buffer);
Run Code Online (Sandbox Code Playgroud)
至于你的第一个例子,传递给的偏移量以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)
Run Code Online (Sandbox Code Playgroud)
第一个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
Run Code Online (Sandbox Code Playgroud)
做最后一个例子
y.setUint32(0, 1)
y.setUint32(4, 2)
// x is now [0, 0, 0, 1, 0, 0, 0, 2, ....]
console.log(y.getUint32(0)) // 1
// this is reading the bytes 0 to 3
// x[0] << 24 + x[1] << 16 + x[2] << 8 + x[3]
// 0 << 24 + 0 << 16 + 0 << 8 + 1 = 1
console.log(y.getUint32(1)) // 256
// this is reading the bytes 1 to 4
// x[1] << 24 + x[2] << 16 + x[3] << 8 + x[4]
// 0 << 24 + 0 << 16 + 1 << 8 + 0 = 256
console.log(y.getUint32(2)) // 65536
// this is reading the bytes 2 to 5
// x[2] << 24 + x[3] << 16 + x[4] << 8 + x[5]
// 0 << 24 + 1 << 16 + 0 << 8 + 0 = 65536
console.log(y.getUint32(3)) // 16777216
// this is reading the bytes 3 to 6
// x[3] << 24 + x[4] << 16 + x[5] << 8 + x[6]
// 1 << 24 + 0 << 16 + 0 << 8 + 0 = 16777216
console.log(y.getUint32(4)) // 2
// this is reading the bytes 4 to 7
// x[4] << 24 + x[5] << 16 + x[6] << 8 + x[7]
// 0 << 24 + 0 << 16 + 0 << 8 + 2 = 2
Run Code Online (Sandbox Code Playgroud)
将相同的逻辑应用于其余部分,希望您的DataView
问题得到解释?
您说您想通过参考 MDN 图并显示大量 0 和 1 将它们打印为字节,您的意思是位吗?你可以像这样打印一个数字
const view = new Uint32Array(100);
Run Code Online (Sandbox Code Playgroud)
或填充到 8 位
const view = new Uint32Array(new ArrayBuffer(400));
Run Code Online (Sandbox Code Playgroud)
打印整个缓冲区,假设你有一个Uint8Array
视图(如果没有的话)
const buffer = new ArrayBuffer(400);
const view1 = new Uint32Array(buffer);
const view2 = new Uint8Array(buffer);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4068 次 |
最近记录: |