【问题标题】:How can source Int16Array values be retained though conversion to Uint8Array如何通过转换为 Uint8Array 保留源 Int16Array 值
【发布时间】:2021-07-26 15:29:53
【问题描述】:

我通过这种格式的函数传递数据

Int16Array > Uint8Array > Int16Array

如何让z和原来的x一样

var x = new Int16Array([17, -45]);
var y = new Uint8Array(x);
var z = new Int16Array(y);

想把z设为[ 17, -45 ]

编辑: 完整示例

const Readable = require('stream').Readable;

const rs = new Readable({
    objectMode: false,
    read(){}
});

var data = new Int16Array([17, -45]);
rs.push(data);

rs.on('data', function(chunk) {
    var result = new Int16Array(chunk);
});

我希望“结果”具有价值[17, -45]

【问题讨论】:

  • 目前还不清楚您要在这里实现什么。如果最终结果再次出现Int16Array,为什么还要进行转换?显然,转换为Uint8Array 是行不通的,因为它会丢失一半的信息。
  • 只转换,因为回调抱怨。 “chunk”参数必须是字符串类型或 Buffer 或 Uint8Array 的实例。收到一个 Int16Array 的实例
  • @moimoi 你在说什么回调?请edit您的问题包括您遇到问题的实际代码。
  • @moimoi 我不适合回答,但你应该不费吹灰之力就问(像往常一样)。

标签: javascript node.js node-streams typed-arrays


【解决方案1】:
Number 16 bit (BE) In binary (BE) Note
17 0x00 0x11 00000000 00010001
-45 0xff 0xd3 11111111 11010011 255,211 in decimal
45 0x00 0xd3 00000000 00101101 The bits are flipped

一个包含两个值的 16 位 TypedArray 需要2 * Int16Array.BYTES_PER_ELEMENT = 4 字节来存储数据。你可以自己检查一下:

console.log(
  arr16 = new Int16Array([17, -45]),
  arr16.buffer
);

[17, -45] // two elements (decimal)
...<11 00 d3 ff> // of 4 bytes total

注意:11 00 & d3 ff 而不是 00 11 & ff d3。顺序不同,因为表示是 Little Endian。不用担心。

如果你将buffer 传递给Int8Array,你会得到:

console.log(
  arr8 = new Uint8Array( arr16.buffer ),
  arr8.buffer
);

[17, 0, 211, 255] // four elements (decimal)
...<11 00 d3 ff> // but same 4 bytes total

注意:实际上 arr8 和 arr16 都指的是确切相同的字节,所以如果你这样做arr16[0]=3arr8[0] 也会改变! p>

倒数现在并不难想象:

new Int16Array( arr8.buffer );
[17, -45] // two elements (decimal)

因此,您的样本将是:

var x = new Int16Array([17, -45]);
var y = new Uint8Array(x.buffer); // the .buffer is important!
var z = new Int16Array(y.buffer);

console.log(x[1] === z[1]); // true;

如果您想要转换为 Node.js 缓冲区而不是 UintArray

// Important to use .buffer here, otherwise it'll use the decimal
// representation of your input, not the actual bytes!
const buffer = Buffer.from(arr16.buffer);

然后你需要添加:

new Int16Array( buffer.buffer )

因为如果你这样做:

new Int16Array( buffer );

那么你实际上是在这样做:

const decimalRepresentationOfBytesInBuffer = [...buffer.values()];
new Int16Array( decimalRepresentationOfBytesInBuffer );
[17, 0, 11, 255] // four elements (decimal)
...<11 00 00 00 d3 00 ff 00> // of 8 bytes total

【讨论】:

  • 也许“十进制表示”并不完全准确,但如果有人觉得他们可以用一种更容易理解的方式说出来,那就更正确了:随意!
  • (new Uint8Array(buffer)).buffer 没有意义,你可以马上做buffer.buffer。 (是的,很奇怪,那是因为nodejs Buffer 也实现了Uint8Array 接口)
  • 啊,我没有想到这一点,尽管 我知道 Buffer 实现了它。我已经编辑了上面的答案以删除多余的构造函数。谢谢你提醒我!
【解决方案2】:

要从类型化数组创建到push into a Readable stream 的缓冲区,请在其.buffer 上使用Buffer.from method

var data = new Int16Array([17, -45]);
var buf = Buffer.from(data.buffer);
rs.push(buf);

您的 data 事件处理程序中的 result 类型数组将需要再次从块的缓冲区构造:

rs.on('data', function(chunk) {
    var result = new Int16Array(chunk.buffer);
});

有关详细信息,请参阅文档中的 Buffers and TypedArrays

【讨论】:

  • 结果是 Int16Array(4) [ 17, 0, 211, 255 ] 如何转换回 [17, -45]
  • 啊,对,“将 Buffer 传递给 TypedArray 构造函数将复制 Buffers 内容,解释为整数数组,而不是目标类型的字节序列。" - 基本上将chunk 视为Uint8Array。这不是你想要的。
猜你喜欢
  • 2016-09-20
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-13
  • 2023-03-28
  • 1970-01-01
相关资源
最近更新 更多