我收到以下代码的错误Offset is outside the bounds of the DataView
let data = [...] // some array of Int16
let buf = new ArrayBuffer(data.length);
let dataView = new DataView(buf);
data.forEach((b, i) => {
dataView.setInt16(i, b);
});
这是Chrome中的调试视图
您会看到i
是47999
,我的DataView
的缓冲区大小是48000
。我在这里想念什么?
答案 0 :(得分:0)
这是因为Int16Array每个元素有2个字节。因此,其.length
的大小将比其缓冲区的实际大小小两倍,而应使用其.byteLength
来创建相同大小的新ArrayBuffer。
另外,设置一个int16实际上将一次设置两个字节。
因此,在某个时候,您的循环将尝试设置一个不存在的字节,并将抛出该错误。
但这还不是您的代码的全部。由于forEach()
的迭代值i
是基于TypedArray的.length
值的,因此您还需要将其乘以TypedArray每个元素的字节数,以在{{1 }}。
DataView.setInt16
现在,我不确定您要使用此代码段做什么,但是要复制您的TypedArray,则必须检查计算机的字节序,然后使用{ {1}},但您也可以简单地这样做:
const data = new Int16Array( [ 0xFFFF, 0xFF00, 0x00FF, 0x000 ] );
console.log( "length:", data.length );
console.log( "byteLength:", data.byteLength );
const buf = new ArrayBuffer(data.byteLength);
const dataView = new DataView(buf);
data.forEach( (b, i) => {
dataView.setInt16( i * data.BYTES_PER_ELEMENT, b );
} );
console.log( new Int16Array( buf ) );
// -1, 255, -256, 0
如果您希望从小字节序转换为大字节序,那么还可以通过首先检查计算机的字节序并在必要时使用DataView.setInt16( byteOffset, value, littleEndian )
来交换值,从而使其比使用DataView更快。
const data = new Int16Array( [ 0xFFFF, 0xFF00, 0x00FF, 0x000 ] );
const buf = data.buffer.slice();
// ensure they are not the same ArrayBuffer
data.fill( 0 );
console.log( "data: ", data ); // 0, 0, 0 ,0
console.log( "copy:", new Int16Array( buf ) );
// -1, 256, 255, 0