Buffer 和 TypedArray 转换导致数据突变?
Buffer and TypedArray conversion causes data mutation?
我正在通过 XHR 加载远程资产并以 arrayBuffers
的形式接收它们。基础数据是 float32
依赖的。我需要对这些数组缓冲区做一些进一步的操作,比如连接和合并。对于这些操作,我正在试验 buffer module.
我发现使用 Buffer 模块和底层 Uint8Array 正在改变预期的 float32
输出
用new Float32Array
构造函数实例化TypedArray
时,数据是正确的。
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, …]
当使用 from
方法初始化 TypedArray
时,数据为空。这是预期的,因为 from
方法需要一个可迭代的数组,而 arrayBuffer
不是。
Float32Array.from(action.payload.arrayBuffer)
Float32Array []
从使用底层 Uint8Array
的 Uint8Array
或 Buffer
转换时,浮点数据会发生变化。
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, …]
最终输出的这种差异完全破坏了我期望 new Float32Array
输出
的工作管道
我正在寻找关于为什么会发生这种情况的解释和教育回应。
这是因为 Uint8 数组(视图)保存的每个值都基于视图转换为完整的 Float32 值,而不是底层 ArrayBuffer。
如果您有一个包含例如 4 个条目的 Uint8Array 视图:
Uint8 -> [1,2,3,4]
在 ArrayBuffer 中它看起来像这样(ArrayBuffer 始终是一个字节数组):
0x01020304
然后发生的事情是,当您将 Uint8 视图转换为 Float32 视图时,使用 view 表示中的值(即 [1,2,3,4]) ,而不是底层的 ArrayBuffer,因此这些条目只是简单地转换为新条目,但在不同的 type 中仍然表示与原始视图表示相同的数字 [1,2,3,4] :
Float32 -> [1,2,3,4] (each entry stored as 32-bit value)
新的 ArrayBuffer 看起来像(手动转换,但你会明白)由 Float32 表示的 4 个字节(32 位)x 4 个值组成 - 还要注意浮点值编码为 IEEE754 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 是来自底层 ArrayBuffer 的 4 个字节,这意味着它们将转换为通过视图显示的不同值。
我正在通过 XHR 加载远程资产并以 arrayBuffers
的形式接收它们。基础数据是 float32
依赖的。我需要对这些数组缓冲区做一些进一步的操作,比如连接和合并。对于这些操作,我正在试验 buffer module.
我发现使用 Buffer 模块和底层 Uint8Array 正在改变预期的 float32
输出
用new Float32Array
构造函数实例化TypedArray
时,数据是正确的。
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, …]
当使用 from
方法初始化 TypedArray
时,数据为空。这是预期的,因为 from
方法需要一个可迭代的数组,而 arrayBuffer
不是。
Float32Array.from(action.payload.arrayBuffer)
Float32Array []
从使用底层 Uint8Array
的 Uint8Array
或 Buffer
转换时,浮点数据会发生变化。
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, …]
最终输出的这种差异完全破坏了我期望 new Float32Array
输出
我正在寻找关于为什么会发生这种情况的解释和教育回应。
这是因为 Uint8 数组(视图)保存的每个值都基于视图转换为完整的 Float32 值,而不是底层 ArrayBuffer。
如果您有一个包含例如 4 个条目的 Uint8Array 视图:
Uint8 -> [1,2,3,4]
在 ArrayBuffer 中它看起来像这样(ArrayBuffer 始终是一个字节数组):
0x01020304
然后发生的事情是,当您将 Uint8 视图转换为 Float32 视图时,使用 view 表示中的值(即 [1,2,3,4]) ,而不是底层的 ArrayBuffer,因此这些条目只是简单地转换为新条目,但在不同的 type 中仍然表示与原始视图表示相同的数字 [1,2,3,4] :
Float32 -> [1,2,3,4] (each entry stored as 32-bit value)
新的 ArrayBuffer 看起来像(手动转换,但你会明白)由 Float32 表示的 4 个字节(32 位)x 4 个值组成 - 还要注意浮点值编码为 IEEE754 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 是来自底层 ArrayBuffer 的 4 个字节,这意味着它们将转换为通过视图显示的不同值。