2013-02-19 50 views
3

如果我在JavaScript中有一个Uint8Array数组,我将如何得到最后四个字节,然后将其转换为int?使用C#我会做这样的事情:如何将数组中的最后4个字节转换为整数?

int count = BitConverter.ToInt32(array, array.Length - 4); 

是否有不等同的方式来使用JavaScript来做到这一点?

+0

@ cIph3r:[Yes](https://developer.mozilla。org/en-US/docs/JavaScript/Typed_arrays/Uint8Array) – Bergi 2013-02-19 17:07:41

+0

@Bergi 好的,但是这只适用于firefox – cIph3r 2013-02-19 17:10:08

+1

@ clph3r,[和Chrome和Safari,Opera和IE10和Android](http:///caniuse.com/#feat=typedarrays).... – 2013-02-19 17:22:11

回答

7

访问底层ArrayBuffer并以其字节片上创建一个新的TypedArray

var u8 = new Uint8Array([1,2,3,4,5,6]); // original array 
var u32bytes = u8.buffer.slice(-4); // last four bytes as a new `ArrayBuffer` 
var uint = new Uint32Array(u32bytes)[0]; 

如果TypedArray不覆盖整个缓冲区,你需要有点棘手,但并不多:

var startbyte = u8.byteOffset + u8.byteLength - Uint32Array.BYTES_PER_ELEMENT; 
var u32bytes = u8.buffer.slice(startbyte, startbyte + Uint32Array.BYTES_PER_ELEMENT); 

这在两种情况下都起作用。

如果您想要的字节适合数据类型的基础缓冲区的对齐边界(例如,您希望基础缓冲区的字节4-8的32位值),则可以避免使用slice()并且只给视图构造函数提供一个byteoffset,就像在@ Bergi的答案中一样。

下面是一个非常轻微测试的函数,它应该得到所需偏移的标量值。如果可能的话,它将避免复制。

function InvalidArgument(msg) { 
    this.message = msg | null; 
} 

function scalarValue(buf_or_view, byteOffset, type) { 
    var buffer, bufslice, view, sliceLength = type.BYTES_PER_ELEMENT; 
    if (buf_or_view instanceof ArrayBuffer) { 
     buffer = buf_or_view; 
     if (byteOffset < 0) { 
      byteOffset = buffer.byteLength - byteOffset; 
     } 
    } else if (buf_or_view.buffer instanceof ArrayBuffer) { 
     view = buf_or_view; 
     buffer = view.buffer; 
     if (byteOffset < 0) { 
      byteOffset = view.byteOffset + view.byteLength + byteOffset; 
     } else { 
      byteOffset = view.byteOffset + byteOffset; 
     } 
     return scalarValue(buffer, view.byteOffset + byteOffset, type); 
    } else { 
     throw new InvalidArgument('buf_or_view must be ArrayBuffer or have a .buffer property'); 
    } 
    // assert buffer instanceof ArrayBuffer 
    // assert byteOffset > 0 
    // assert byteOffset relative to entire buffer 
    try { 
     // try in-place first 
     // only works if byteOffset % slicelength === 0 
     return (new type(buffer, byteOffset, 1))[0] 
    } catch (e) { 
     // if this doesn't work, we need to copy the bytes (slice them out) 
     bufslice = buffer.slice(byteOffset, byteOffset + sliceLength); 
     return (new type(bufslice, 0, 1))[0] 
    } 
} 

你会使用这样的:

// positive or negative byte offset 
// relative to beginning or end *of a view* 
100992003 === scalarValueAs(u8, -4, Uint32Array) 
// positive or negative byte offset 
// relative to the beginning or end *of a buffer* 
100992003 === scalarValue(u8.buffer, -4, Uint32Array) 
+0

+1,非常好。然而,如果'u8'是一个缓冲区上有偏移量的视图,它就不会工作,这需要特殊处理。 – Bergi 2013-02-19 17:45:29

5

你有个例子吗?我认为这会做到这一点:

var result = ((array[array.length - 1]) | 
       (array[array.length - 2] << 8) | 
       (array[array.length - 3] << 16) | 
       (array[array.length - 4] << 24)); 
+0

使用'[255,255,255,255]'会因某种原因使用此代码而产生'-1'。 – Jespertheend 2016-07-02 21:31:40

+0

@Jespertheend结果是'-1',因为它的签名。添加一个无符号右移运算符'>>> 0'将结果转换为无符号值('4294967295')。 – SammieFox 2017-09-04 15:22:40

+0

嗯,这是有道理的。 – Jespertheend 2017-09-04 19:01:27

3

有点不雅,但如果你可以做到手动根据endianess。

小尾数:

var count = 0; 
// assuming the array has at least four elements 
for(var i = array.length - 1; i >= array.length - 4; i--) 
{ 
    count = count << 8 + array[i]; 
} 

大端:

var count = 0; 
// assuming the array has at least four elements 
for(var i = array.length - 4; i <= array.length - 1 ; i++) 
{ 
    count = count << 8 + array[i]; 
} 

这可以扩展到其他数据长度

编辑:感谢David指出我的错别字

+1

应该是'.length'而不是'.Length' – 0x499602D2 2013-02-19 17:15:11

1

创建一个Uint32Array应该更有效率在同一ArrayBuffer和直接访问32位数字:

var uint8array = new Uint8Array([1,2,3,4,5,6,7,8]); 
var uint32array = new Uint32Array(
        uint8array.buffer, 
        uint8array.byteOffset + uint8array.byteLength - 4, 
        1 // 4Bytes long 
       ); 
return uint32array[0]; 
+0

不幸的是,似乎你不能在同一个缓冲区上创建一个不同类型的新视图,除非第二个参数是新视图长度的倍数。例如。在一个8字节的缓冲区上,尽管它看起来像是一个任意的限制,但仍然失败:'new Uint32Array(buffer,2,1)' – 2013-02-19 17:48:45

+0

@FrancisAvila:感谢提示,如果是非4Byte多重缓冲区,切片。我现在修复了我的代码(上述工作),我忘记了我需要从byteLength中减去* 4 *以获得32位: -/ – Bergi 2013-02-19 18:00:42

0
var a = Uint8Array(6) 
a.set([1,2,8,0,0,1]) 

i1 = a[a.length-4]; 
i2 = a[a.length-3]; 
i3 = a[a.length-2]; 
i4 = a[a.length-1]; 

console.log(i1<<24 | i2<<16 | i3<<8 | i4); 
相关问题