偏移量在 DataView 的边界之外,调试器显示它在边界内
Offset is outside the bounds of the DataView, the debugger shows it is inside the bounds
我收到以下代码的错误 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
。我在这里错过了什么?
这是因为 Int16Array 每个元素有 2 个字节。所以它的 .length
将比其缓冲区的实际大小小两倍,使用它的 .byteLength
来创建一个相同大小的新 ArrayBuffer。
另外,设置一个 int16 实际上会一次设置两个字节。
所以在某些时候,您的循环会尝试设置一个不存在的字节,并且会抛出该错误。
但这不是您的代码的全部。由于 forEach()
的迭代值 i
是基于 TypedArray 的 .length
值,您还需要将其乘以 TypedArray 的每个元素的字节数以在 [=18] 中设置正确的偏移量=].
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
现在,我不确定你想用这个片段做什么,但是要复制你的 TypedArray,你必须检查计算机的字节序,然后使用第三个参数DataView.setInt16( byteOffset, value, littleEndian )
,但你也可以简单地做:
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
如果您想从小端交换到大端,那么您还可以通过首先检查计算机的字节序并在必要时使用 .map
交换值来使其比使用 DataView 更快。
const data = new Int16Array( [ 0xFFFF, 0xFF00, 0x00FF, 0x000 ] );
// check for the computer's endianness
const is_little_endian = new Uint8Array( new Uint32Array( [ 0x12345678 ] ).buffer )[ 0 ] === 0x78;
console.log( is_little_endian );
const buf = is_little_endian ?
data.map( (val) => (val<<8) | (val>>8) & 0xFF ).buffer : 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, 255, -256, 0
我收到以下代码的错误 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
。我在这里错过了什么?
这是因为 Int16Array 每个元素有 2 个字节。所以它的 .length
将比其缓冲区的实际大小小两倍,使用它的 .byteLength
来创建一个相同大小的新 ArrayBuffer。
另外,设置一个 int16 实际上会一次设置两个字节。
所以在某些时候,您的循环会尝试设置一个不存在的字节,并且会抛出该错误。
但这不是您的代码的全部。由于 forEach()
的迭代值 i
是基于 TypedArray 的 .length
值,您还需要将其乘以 TypedArray 的每个元素的字节数以在 [=18] 中设置正确的偏移量=].
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
现在,我不确定你想用这个片段做什么,但是要复制你的 TypedArray,你必须检查计算机的字节序,然后使用第三个参数DataView.setInt16( byteOffset, value, littleEndian )
,但你也可以简单地做:
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
如果您想从小端交换到大端,那么您还可以通过首先检查计算机的字节序并在必要时使用 .map
交换值来使其比使用 DataView 更快。
const data = new Int16Array( [ 0xFFFF, 0xFF00, 0x00FF, 0x000 ] );
// check for the computer's endianness
const is_little_endian = new Uint8Array( new Uint32Array( [ 0x12345678 ] ).buffer )[ 0 ] === 0x78;
console.log( is_little_endian );
const buf = is_little_endian ?
data.map( (val) => (val<<8) | (val>>8) & 0xFF ).buffer : 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, 255, -256, 0