Buffer和TypedArray转换导致数据突变?

时间:2017-12-11 04:20:27

标签: javascript node.js buffer typed-arrays

我正在通过XHR加载远程资产并将其作为arrayBuffers接收。基础数据依赖于float32。我需要对这些数组缓冲区进行一些进一步的操作,比如连接和合并。对于这些操作,我正在试验buffer module

我发现使用Buffer模块和底层的Uint8Array正在改变预期的float32输出

使用TypedArray构造函数实例化new Float32Array时,数据是正确的。

new Float32Array(action.payload.arrayBuffer)
Float32Array(9072) [-5, 35, -5, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 34, -5, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 35, -2, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 34, -2, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 35, -2, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 34, -5, 255, 127, 128, 128, 1, 0.2666666805744171, 0.2666666805744171, 0.2666666805744171, 1, -5, 38, -2, 255, 127, 128, 128, 2, 0.9411764740943909, 0.3686274588108063, 0.10980392247438431, 1, -5, 34, -2, 255, 127, 128, 128, 2, 0.9411764740943909, 0.3686274588108063, 0.10980392247438431, 1, -5, 38, 1, 255, …]

使用TypedArray方法初始化from时,数据为空。这是预期的,因为from方法需要一个可迭代的数组,arrayBuffer不是。

Float32Array.from(action.payload.arrayBuffer)
Float32Array []

从使用基础Uint8Array的{​​{1}}或Buffer进行转换时,浮动数据会发生变异。

Uint8Array

最终输出的这种差异完全打破了我期望Float32Array.from(new Uint8Array(action.payload.arrayBuffer)) Float32Array(36288) [0, 0, 160, 192, 0, 0, 12, 66, 0, 0, 160, 192, 0, 0, 127, 67, 0, 0, 254, 66, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 128, 63, 137, 136, 136, 62, 137, 136, 136, 62, 137, 136, 136, 62, 0, 0, 128, 63, 0, 0, 160, 192, 0, 0, 8, 66, 0, 0, 160, 192, 0, 0, 127, 67, 0, 0, 254, 66, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 128, 63, 137, 136, 136, 62, 137, 136, 136, 62, 137, 136, 136, 62, 0, 0, 128, 63, 0, 0, 160, 192, …] Float32Array.from(Buffer.from(action.payload.arrayBuffer)) Float32Array(36288) [0, 0, 160, 192, 0, 0, 12, 66, 0, 0, 160, 192, 0, 0, 127, 67, 0, 0, 254, 66, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 128, 63, 137, 136, 136, 62, 137, 136, 136, 62, 137, 136, 136, 62, 0, 0, 128, 63, 0, 0, 160, 192, 0, 0, 8, 66, 0, 0, 160, 192, 0, 0, 127, 67, 0, 0, 254, 66, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 128, 63, 137, 136, 136, 62, 137, 136, 136, 62, 137, 136, 136, 62, 0, 0, 128, 63, 0, 0, 160, 192, …] 输出

的工作流程

我正在寻找关于为什么会发生这种情况的解释和教育回应。

1 个答案:

答案 0 :(得分:1)

这是因为Uint8数组(视图)保存的每个值都会根据视图而不是基础ArrayBuffer转换为完整的Float32值。

如果您有一个Uint8Array视图,其中包含4个条目:

Uint8 -> [1,2,3,4]

在ArrayBuffer中它看起来像这样(ArrayBuffer总是一个字节数组):

0x01020304

当您将Uint8视图转换为Float32视图时,会使用视图表示中的值(即[1,2,3,4]),而不是基础ArrayBuffer ,所以这些条目只是转换为新条目,但在不同的类型中仍然代表与原始视图相同的数字[1,2,3,4]:

Float32 -> [1,2,3,4]   (each entry stored as 32-bit value)

新的ArrayBuffer看起来像(手动转换,但你会得到这个想法)由Float32代表的4个字节(32位)x 4值组成 - 还要注意浮点值是用{{3为Float32类型表示的每个数字使用4个字节的格式:

0x00003F80 00000040 00004040 00004080 (=1,2,3,4 as IEEE754 encoded floating point values)

您还可以从新的基础ArrayBuffer的字节大小(来自问题中的数字)中看到这一点:

9,072 x 4 = 36,288 bytes

为了获得结果,您希望必须通过其buffer属性直接使用缓冲区:

new Float32Array(uint8array.buffer);  // notice .buffer -> actual ArrayBuffer

这与你在问题的第一行中的方式相同:

new Float32Array(action.payload.arrayBuffer);

字节顺序是这里的一个方面,但是因为直接从XHR使用Float32视图的数字是正确的,所以在这种情况下这可能不是问题。

所以简而言之:没有发生突变,但是不同的类型(通过视图)需要不同的字节数,在这种情况下,Uint8来自底层ArrayBuffer的单个字节和来自相同的Float32 4个字节,这意味着它们将通过视图转换为不同的值。