2013-02-19 49 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); 
相關問題