2012-10-03 116 views
46

我得到了一個webSocket通信,我收到base64編碼的字符串,將其轉換爲uint8並在其上工作,但現在我需要發回,我得到了uint8數組,並且需要將其轉換爲base64字符串,因此我可以發送它。 我該如何做這個轉換?如何將uint8數組轉換爲base64編碼字符串?

+0

[MDN實現的用於Uint8array/ArrayBuffer <-> BASE64](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding#Solution_.232_.E2.80.93_rewriting_atob%28%29_and_btoa% 28%29_using_TypedArrays_and_UTF-8) – JLRishe

回答

106

如果您的瀏覽器已經TextDecoder然後使用:

var u8 = new Uint8Array([65, 66, 67, 68]); 
var decoder = new TextDecoder('utf8'); 
var b64encoded = btoa(decoder.decode(u8)); 

如果您需要支持browsers that do not have TextDecoder (目前只是IE和Edge),那麼最好的選擇是使用TextDecoder polyfill

如果你的字符串是純ASCII和多字節不統一/ UTF-8則有是使用使用String.fromCharCode一個簡單的替代方案,應普遍得到公平的支持:

var u8 = new Uint8Array([65, 66, 67, 68]); 
var b64encoded = btoa(String.fromCharCode.apply(null, u8)); 

而到了的base64字符串解碼回到Uint8Array:

var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) { 
    return c.charCodeAt(0); })); 

如果你有非常大的數組緩衝區,則應用可能會失敗,您可能需要塊緩衝區(基於一個張貼@RohitSengar)。再次,注意,如果你的緩衝區只包含非多字節ASCII字符,這是唯一正確的:

function Uint8ToString(u8a){ 
    var CHUNK_SZ = 0x8000; 
    var c = []; 
    for (var i=0; i < u8a.length; i+=CHUNK_SZ) { 
    c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ))); 
    } 
    return c.join(""); 
} 
// Usage 
var u8 = new Uint8Array([65, 66, 67, 68]); 
var b64encoded = btoa(Uint8ToString(u8)); 
+4

這應該是公認的答案。 – jutky

+0

完美,它確實有效。 –

+3

這適用於我在Firefox中,但鉻扼流圈與「未捕獲RangeError:超過最大調用堆棧大小」(做btoa)。 –

-3

如果你想要的只是一個base64編碼器的JS實現,所以你可以發回數據,你可以試試btoa函數。

b64enc = btoa(uint); 

關於btoa的一些快速註釋 - 這是非標準的,所以瀏覽器不會強迫它支持它。 但是,大多數瀏覽器都這樣。最重要的是,至少。 atob是相反的轉換。

如果你需要一個不同的實現,或者你發現瀏覽器不知道你在說什麼的邊緣情況,尋找一個JS的base64編碼器不會太難。

我覺得有他們的3掛在我公司的網站,出於某種原因...

+0

謝謝,我沒有嘗試過。 –

+10

幾個音符。 btoa和atob實際上是HTML5標準化過程的一部分,而且大多數瀏覽器都以大致相同的方式支持它們。其次,btoa和atob只能使用字符串。在Uint8Array上運行btoa將首先使用toString()將緩衝區轉換爲字符串。這導致字符串「[object Uint8Array]」。這可能不是預期的。 – kanaka

+1

@CaioKeto你可能想考慮改變你選擇的答案。這個答案不正確。 – kanaka

13
function Uint8ToBase64(u8Arr){ 
    var CHUNK_SIZE = 0x8000; //arbitrary number 
    var index = 0; 
    var length = u8Arr.length; 
    var result = ''; 
    var slice; 
    while (index < length) { 
    slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length)); 
    result += String.fromCharCode.apply(null, slice); 
    index += CHUNK_SIZE; 
    } 
    return btoa(result); 
} 

如果你有一個非常大的Uint8Array,你可以使用這個函數。這是用於Javascript的,在FileReader的readAsArrayBuffer的情況下可以是有用的。

+2

有趣的是,在Chrome中,我在一個300kb的緩衝區中定時執行了這個操作,並發現像你這樣做的區塊會比逐字節地慢一點。這讓我感到驚訝。 – Matt

+0

@Matt有趣。與此同時,Chrome可能會檢測到此轉換並對其進行了特定優化,並且數據分塊可能會降低其效率。 – kanaka

+2

這不安全,是嗎?如果我的塊的邊界穿過多字節的UTF8編碼字符,那麼[fromCharCode()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode)將不會是能夠從邊界兩側的字節創建合理的字符,是嗎? – Jens

7

非常簡單的解決方案和JavaScript測試!

ToBase64 = function (u8) { 
    return btoa(String.fromCharCode.apply(null, u8)); 
} 

FromBase64 = function (str) { 
    return atob(str).split('').map(function (c) { return c.charCodeAt(0); }); 
} 

var u8 = new Uint8Array(256); 
for (var i = 0; i < 256; i++) 
    u8[i] = i; 

var b64 = ToBase64(u8); 
console.debug(b64); 
console.debug(FromBase64(b64)); 
+0

最乾淨的解決方案! – Abdel

0

我會添加另一個解決方案,使用不可打印的範圍。我的猜測是這比鏈接TextEncoderbtoa快。

var blob = new Blob([ uint8ArrayBuffer ], { type: "image/jpeg" }); 
var imageUrl = URL.createObjectURL(blob); 

這是使用HTML5 API,所以當然不會在Node或其他基於JS的服務器上工作。你可以看到一個演示here

相關問題