ArrayBuffer到base64编码的字符串

zah*_*eer 168 javascript base64 encoding arraybuffer

我需要一种有效的(读取本机)方式将ArrayBuffer转换为需要在多部分帖子上使用的base64字符串.

小智 196

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 );
}
Run Code Online (Sandbox Code Playgroud)

但是,非本机实现更快,例如https://gist.github.com/958841 请参阅http://jsperf.com/encoding-xhr-image-data/6

  • 我尝试了链接中的非本机实现,转换1M大小的缓冲区需要1分半,而上面的循环代码只需要1秒. (8认同)
  • @JoãoEduardoSoareseSilva 因为不是每个人都在使用 Node - Node 的“Buffer”在浏览器中不存在。 (6认同)
  • 我喜欢这种方法的简单性,但所有这些字符串连接都可能代价高昂。在 Firefox、IE 和 Safari 上,似乎构建了一个字符数组并在最后用 `join()` 连接它们的速度要快得多(但在 Chrome 上要慢得多):http://jsperf.com/tobase64-实现 (4认同)
  • 我想知道为什么每个人都避免使用本机缓冲区 `toString('base64')` 方法。 (2认同)

GOT*_*O 0 86

这对我来说很好:

var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
Run Code Online (Sandbox Code Playgroud)

在ES6中,语法更简单:

let base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
Run Code Online (Sandbox Code Playgroud)

正如注释中所指出的,当ArrayBuffer很大时,这种方法可能会导致某些浏览器出现运行时错误.在任何情况下,确切的大小限制都取决于实现.

  • 我更喜欢这种方法以简洁,但得到"最大调用堆栈大小超出错误".上面的循环技术可以解决这个问题. (34认同)
  • 我也得到了一个堆栈大小错误,所以我使用了mobz的答案,它运行得很好. (13认同)
  • 它不适用于大缓冲区.稍作修改使它工作:`btoa([] .reduce.call(new Uint8Array(bufferArray),function(p,c){return p + String.fromCharCode(c)},''))` (11认同)
  • 我正在尝试使用 angualrjs 和 webapi2 上传 50mb pdf 文件。我正在使用上面的代码,上传文件后,页面崩溃并挂起。下面的代码行,我被使用,但在 webapi 方法中得到空值。“var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));” 请提出任何想法... (2认同)
  • @Kugel`btoa`对于代码范围为0-255的字符是安全的,因为这是这种情况(想想`Uint8Array`中的8). (2认同)
  • FWIW,在 Chrome 104 上使用 `...` 比使用 `apply` 慢得多。 (2认同)

Joã*_*lva 47

OP 没有指定运行环境,但如果您使用 Node.JS,有一个非常简单的方法可以做到这一点。

根据 Node.JS 官方文档: https://nodejs.org/api/buffer.html#buffer_buffers_and_character_encodings

// This step is only necessary if you don't already have a Buffer Object
const buffer = Buffer.from(yourArrayBuffer);

const base64String = buffer.toString('base64');
Run Code Online (Sandbox Code Playgroud)

此外,如果您在 Angular 下运行,该类Buffer也将在浏览器环境中可用。

  • @jvatic我明白了,OP没有明确指定运行环境,所以我的答案不正确,他只标记了“Javascript”。所以我更新了我的答案以使其更加简洁。我认为这是一个重要的答案,因为我正在寻找如何做到这一点,但无法找到问题的最佳答案。 (5认同)
  • 您的答案仅适用于 NodeJS,在浏览器中不起作用。 (2认同)

cui*_*ing 33

还有另一种使用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"
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不能保证有效。根据 https://w3c.github.io/FileAPI/#issue-f80bda5b `readAsDataURL` 理论上可以返回百分比编码的 dataURI (看起来 [jsdom](https://github.com/ jsdom/jsdom/问题/2269)) (3认同)

gku*_*unz 33

对于那些喜欢它的人来说,这是另一个使用Array.reduce它不会导致堆栈溢出:

var base64 = btoa(
  new Uint8Array(arrayBuffer)
    .reduce((data, byte) => data + String.fromCharCode(byte), '')
);
Run Code Online (Sandbox Code Playgroud)

  • 不确定这是否真的很性感。毕竟,您正在创建`&lt;缓冲区中的字节数&gt;` 新字符串。 (8认同)
  • 另一种选择:`btoa(Array.from(new Uint8Array(arraybuffer)).map(b =&gt; String.fromCharCode(b)).join(''))`。 (2认同)

小智 21

var blob = new Blob([arrayBuffer])

var reader = new FileReader();
reader.onload = function(event){
   var base64 =   event.target.result
};

reader.readAsDataURL(blob);
Run Code Online (Sandbox Code Playgroud)

  • 我认为您还需要删除 DataURL 标头 (`data:*/*;base64,`) 以仅获取 Base64 字符串。请参阅 [MDN 文档](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL) (5认同)
  • 请为您的答案添加一些解释。这段代码是什么意思? (3认同)

Eli*_*gas 12

我用过这个并且适合我.

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是我发现的唯一对我有用的解决方案。 (4认同)

che*_*ish 10

我对此的建议是不使用原生btoa策略 - 因为它们没有正确编码所有ArrayBuffer的...

重写DOM atob()和btoa()

由于DOMStrings是16位编码的字符串,因此在大多数浏览器中,如果字符超出8位ASCII编码字符的范围,则在Unicode字符串上调用window.btoa将导致字符超出范围异常.

虽然我从未遇到过这个确切的错误,但我发现许多ArrayBuffer我试过编码的编码错误.

我会使用MDN推荐或要点.

  • 所有数组缓冲区都应该使用其他答案中的策略进行良好编码,atob/btoa 只是包含大于 0xFF 字符的文本的问题(根据定义,字节数组不会)。MDN 警告不适用,因为在其他答案中使用该策略时,您可以保证有一个仅包含 ASCII 字符的字符串,因为 Uint8Array 中的任何值都保证在 0 到 255 之间,这意味着保证 String.fromCharCode返回一个未超出范围的字符。 (11认同)
  • 非常重要,这里有很多片段推荐了错误的东西!我多次看到这个错误,人们盲目地使用 atob 和 btoa。 (3认同)

小智 6

下面是两个简单的函数,用于将Uint8Array转换为Base64 String并再次返回

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

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

  • 这看起来不错,但如果数组太大,则会抛出超出最大调用堆栈大小的错误。 (3认同)
  • 这是一个令人困惑的答案。这看起来不像有效的 JavaScript,Uint8Array 是 ArrayBuffer 吗? (2认同)

小智 6

这对我有用:

Buffer.from(myArrayBuffer).toString("base64");
Run Code Online (Sandbox Code Playgroud)


Hen*_*wan 5

如果您可以添加库,base64-arraybuffer

yarn add base64-arraybuffer
Run Code Online (Sandbox Code Playgroud)

然后:

  • encode(buffer)- 将ArrayBuffer编码为base64字符串
  • decode(str)- 将base64字符串解码为ArrayBuffer