2015-06-05 93 views
0

我有一個由Uint8s組成的數據的ArrayBuffer。每個都是網絡字節順序(big-endian)。我的目標是將每個Uint8轉換爲小端順序,然後將它們放回到ArrayBuffer中。ArrayBuffer中的存儲類型數組

我知道我可以很容易地通過使用一個類型數組個體的uint分離,像這樣:

var uintArr = new Uint8Array(ArrayBuffer); 

從那裏我可以交換每個項目的字節序,並且具有小端的陣列Uint8s。

我不知道如何將該數組重新放入ArrayBuffer中。

有沒有辦法在Javascript中做到這一點?

回答

2

ArrayBuffer是所有視圖的通用字節數組。類型化數組只是意味着數組上有一個關聯類型,例如uint8,int16等。所有的Uin8Array,Int32Array等都是在ArrayBuffer之上的視圖,以便使用它們表示的類型進行讀寫。 (U)int8數組沒有字節順序,因爲它們是單個字節(即無需重新排序)。字節需要表示更廣泛的內容,如(u)int-16或-32(在ES7之前不支持64位整數,但確實有32位和64位IEEE浮點數)。

任何您通過視圖讀取或寫入的內容都會返回到它們指向的同一個ArrayBuffer中 - 您甚至可以爲同一個緩衝區創建多個視圖。

要交換順序爲16位則可以使用Uint16Array視圖和交換手動簡單地讀取ArrayBuffer:

var buffer16 = new Uint16Array(buffer); // use same buffer as for the Uin8Array view 

for(var i = 0, v; i < buffer16.length; i++) { 
    v = buffer16[i]; 
    buffer16[i] = ((v & 0xff) << 8) | ((v & 0xff00) >>> 8); // mask and shift the two bytes 
} 

如果你有一個8位的視圖相同的緩衝液你現在可以讀取單個字節與新的訂單。

對於32位,你會怎麼做:

var buffer32 = new Uint32Array(buffer); 

for(var i = 0, v; i < buffer32.length; i++) { 
    v = buffer32[i]; 
    buffer32[i] = ((v & 0xff) << 24) |  // mask, move byte 0 to 3 
       ((v & 0xff00) << 8) |  // mask, move byte 1 to 2 
       ((v & 0xff0000) >>> 8) | // mask, move byte 2 to 1 unsigned 
       ((v & 0xff000000) >>> 24); // mask, move byte 3 to 0 unsigned 
} 

然而,這些意見需要一致的緩衝器意味着緩衝區的長度(U)INT16必須爲偶數長度保持一致,而32位必須是對齊到4個字節。

如果緩衝器不是,則可以改爲使用一個數據視圖閱讀和在一些性能爲代價寫任何長度,在任何位置:

var view = new DataView(buffer); 
var alignedLength = ((buffer.length/2)|0) * 2; // aligned to 16-bit 

// 16-bit 
for(var i = 0, v; i < alignedLength; i += 2) { 
    v = view.getUint16(i, false); // read as big-endian 
    view.setUint16(i, v, true); // write as little-endian 
} 

和32位使用getUint32/setUint32代替,注意,如果ArrayBuffer未對齊到2或4個字節(通常您會對齊buffer.length並在循環中使用它,如圖所示,請使用4爲32位)。

如果源緩衝區包含混合長度(例如,如果它包含原始二進制文件),則必須根據文件格式規範解析每個值。爲此,請使用DataView。

例子

var buffer = new ArrayBuffer(4), 
 
    b8 = new Uint8Array(buffer), 
 
    b16 = new Uint16Array(buffer), 
 
    b32 = new Uint32Array(buffer), 
 
    view = new DataView(buffer); 
 

 
setData(); 
 
show("Original unsigned big-endian"); 
 

 

 
// swap the value using 16-bit array 
 
for(var i = 0, v; i < b16.length; i++) { 
 
    v = b16[i]; 
 
    b16[i] = ((v & 0xff) << 8) | ((v & 0xff00) >>> 8); 
 
} 
 
show("Byte-order swapped 16-bits"); 
 

 
setData(); 
 
for(var i = 0, v; i < b32.length; i++) { 
 
    v = b32[i]; 
 
    b32[i] = ((v & 0xff) << 24) | 
 
      ((v & 0xff00) << 8) | 
 
      ((v & 0xff0000) >>> 8) | 
 
      ((v & 0xff000000) >>> 24); 
 
} 
 
show("Byte-order swapped 32-bits"); 
 

 
setData(); 
 
for(var i = 0, v; i < buffer.byteLength; i += 2) { 
 
    v = view.getUint16(i, false); // big-endian 
 
    view.setUint16(i, v, true); // little-endian 
 
} 
 
show("Byte-order swapped 16-bit using DataView"); 
 

 
setData(); 
 
for(var i = 0, v; i < buffer.byteLength; i += 4) { 
 
    v = view.getUint32(i, false); // big-endian 
 
    view.setUint32(i, v, true); // little-endian 
 
} 
 
show("Byte-order swapped 32-bit using DataView"); 
 

 

 
function valToHex(v) { 
 
    return (v>>>0).toString(16) 
 
} 
 

 
function setData() { 
 
    b8[0] = 255; // "network" order/big.endian 0xff804020 
 
    b8[1] = 128; 
 
    b8[2] = 64; 
 
    b8[3] = 32; 
 
} 
 

 
function show(pre) { 
 
    document.write(pre + ": "); 
 
    document.write("0x" + valToHex(b8[0])); 
 
    document.write(valToHex(b8[1])); 
 
    document.write(valToHex(b8[2])); 
 
    document.write(valToHex(b8[3]) + "<br>"); 
 
}
body {font:16px monospace}

+0

笑我真的沒有想到。當然,Uint8s只是單個字節。感謝您的詳細和徹底的答覆。 – user2871915

相關問題