2012-02-13 158 views

回答

142
function _arrayBufferToBase64(buffer) { 
    var binary = ''; 
    var bytes = new Uint8Array(buffer); 
    var len = bytes.byteLength; 
    for (var i = 0; i < len; i++) { 
     binary += String.fromCharCode(bytes[ i ]); 
    } 
    return window.btoa(binary); 
} 

但是,非本機實現方式更快,例如, https://gist.github.com/958841 看到http://jsperf.com/encoding-xhr-image-data/6

+4

我嘗試了鏈接的非本地實現,它花了1分半鐘來轉換一個1M大小的緩衝區,而上面的循環代碼只花了1秒。 – cshu 2013-06-28 18:12:31

+0

我喜歡這種方法的簡單性,但所有的字符串連接都可能是昂貴的。它看起來像構建一個字符數組,並且在最後使用join()方法在Firefox,IE和Safari上速度要快得多(但在Chrome上速度要慢很多):http://jsperf.com/tobase64-實現 – JLRishe 2014-05-14 09:30:37

+0

我正在使用此功能陣列緩衝區base64轉換,但我無法取回數組緩衝區。我在這裏聲明瞭一個_base64ToArrayBuffer()函數:http://codeshare.io/PT4pb,但是這給了我一個錯誤,因爲:'在'Window'上無法執行'atob':要解碼的字符串編碼不正確。 – bawejakunal 2015-07-11 13:27:50

46

這對我工作得很好:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer))); 

在ES6,語法是有點簡單:

let base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))); 

正如在評論中指出,這種方法可能會導致當ArrayBuffer較大時,在某些瀏覽器中出現運行時錯誤。在任何情況下,確切的大小限制都取決於實現。

+26

我更喜歡這種方法的簡潔性,但得到「最大調用堆棧大小超出錯誤」。上面的循環技術可以解決這個問題。 – Jay 2012-09-07 12:26:52

+11

我也遇到堆棧大小錯誤,所以我使用mobz的答案,它的工作很好。 – 2013-09-03 01:34:07

+0

這工作簡潔,謝謝 – duckegg 2014-07-06 16:39:19

-3
function _arrayBufferToBase64(uarr) { 
    var strings = [], chunksize = 0xffff; 
    var len = uarr.length; 

    for (var i = 0; i * chunksize < len; i++){ 
     strings.push(String.fromCharCode.apply(null, uarr.subarray(i * chunksize, (i + 1) * chunksize))); 
    } 

    return strings.join(""); 
} 

這是更好的,如果你使用JSZip用於解壓縮歸檔從字符串

+0

有什麼錯? – RouR 2015-07-27 09:07:09

+0

這個函數並沒有做它應該做的事情:https://jsfiddle.net/as9t9ebf/ – 2015-12-26 21:55:50

6

我提出這一建議是不要使用本地btoa策略,因爲它們不正確編碼所有ArrayBuffer的...

rewrite the DOMs atob() and btoa()

由於DOMStrings是16位編碼的字符串,在大多數瀏覽器上一個Unicode字符串調用window.btoa會引起CHARAC如果字符超出8位ASCII編碼字符的範圍,則超出範圍異常。

雖然我從來沒有遇到過這種確切的錯誤,我發現許多我試圖編碼的ArrayBuffer的已編碼不正確。

我會使用MDN建議或要點。

+0

'btoa'不適用於String,但是OP要求'ArrayBuffer'。 – tsh 2017-06-17 03:18:21

+1

非常多,這裏有很多片段推薦錯誤的東西!我多次看到這個錯誤,人們盲目地使用atob和btoa。 – Kugel 2017-08-24 04:53:23

11

還有另一種異步方式使用Blob和的FileReader。

我沒有測試性能。但這是一種不同的思考方式。

function arrayBufferToBase64(buffer, callback) { 
    var blob = new Blob([buffer],{type:'application/octet-binary'}); 
    var reader = new FileReader(); 
    reader.onload = function(evt){ 
     var dataurl = evt.target.result; 
     callback(dataurl.substr(dataurl.indexOf(',')+1)); 
    }; 
    reader.readAsDataURL(blob); 
} 

//example: 
var buf = new Uint8Array([11,22,33]); 
arrayBufferToBase64(buf, console.log.bind(console)); //"CxYh" 
6

我用這個,併爲我工作。

function arrayBufferToBase64(buffer) { 
    var binary = ''; 
    var bytes = new Uint8Array(buffer); 
    var len = bytes.byteLength; 
    for (var i = 0; i < len; i++) { 
     binary += String.fromCharCode(bytes[ i ]); 
    } 
    return window.btoa(binary); 
} 



function base64ToArrayBuffer(base64) { 
    var binary_string = window.atob(base64); 
    var len = binary_string.length; 
    var bytes = new Uint8Array(len); 
    for (var i = 0; i < len; i++)  { 
     bytes[i] = binary_string.charCodeAt(i); 
    } 
    return bytes.buffer; 
} 
+0

不安全。請參閱@chemoish answer – Kugel 2017-08-24 04:57:32

0

可以通過使用Array.prototype.slice導出從ArrayBuffer正常陣列。 使用像Array.prototype.map這樣的函數將字節轉換爲字符並將它們一起轉換爲形成字符串。

function arrayBufferToBase64(ab){ 

    var dView = new Uint8Array(ab); //Get a byte view   

    var arr = Array.prototype.slice.call(dView); //Create a normal array   

    var arr1 = arr.map(function(item){   
     return String.fromCharCode(item); //Convert 
    }); 

    return window.btoa(arr1.join('')); //Form a string 

} 

由於沒有字符串連接在其中運行,因此此方法更快。

+0

不安全。看到@chemoish回答 – Kugel 2017-08-24 04:58:02

17

對於那些誰喜歡總之,這裏是一個另一種使用Array.reduce這不會導致堆棧溢出:

var base64 = btoa(
    new Uint8Array(arrayBuffer) 
    .reduce((data, byte) => data + String.fromCharCode(byte), '') 
); 
+0

性感! – Kano 2018-01-04 09:36:43

1

下面是兩個簡單的功能Uint8Array轉換爲Base64編碼字符串,然後再返回

arrayToBase64String(a) { 
    return btoa(String.fromCharCode(...a)); 
} 

base64StringToArray(s) { 
    let asciiString = atob(s); 
    return new Uint8Array([...asciiString].map(char => char.charCodeAt(0))); 
}