ArrayBuffer到base64编码的字符串


Answers:


221
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


10
我从链接尝试了非本地实现,转换1M大小的缓冲区花了1分半钟,而上面的循环代码仅花了1秒。
cshu 2013年

1
我喜欢这种方法的简单性,但是所有的字符串连接都是昂贵的。看起来join()在Firefox,IE和Safari上构建字符数组并在结尾处输入它们明显更快(但在Chrome上却慢得多):jsperf.com/tobase64-implementations
JLRishe 2014年

我正在使用此函数进行数组缓冲区到base64的转换,但是我无法找回数组缓冲区。我在这里wrriten一个_base64ToArrayBuffer()函数:codeshare.io/PT4pb但是这给了我一个错误:Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.
bawejakunal

此JSZip无法正常工作。我找到了另一种方式github.com/michael/github/issues/137
RouR

1
我正在尝试使用angualrjs和webapi2上传50mb pdf文件。我正在使用上面的代码,上传文件后,页面崩溃并挂起。在下面的代码行中,我使用了webapi方法中的空值。“ var base64String = btoa(String.fromCharCode.apply(null,新的Uint8Array(arrayBuffer)));” 请提出任何想法...
prabhakaran S

101

这对我来说很好:

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

在ES6中,语法更加简单:

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

正如评论中指出的那样,当ArrayBuffer较大时,此方法可能会导致某些浏览器出现运行时错误。确切的大小限制在任何情况下都取决于实现。


38
为了简洁起见,我更喜欢此方法,但是会收到“最大调用堆栈大小超出错误”的信息。上面的循环技术可以解决这个问题。
周杰伦

13
我也遇到了堆栈大小错误,因此我使用了mobz的答案,效果很好。
大卫·琼斯

12
它不适用于大型缓冲区。进行轻微修改以使其起作用:btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c){return p+String.fromCharCode(c)},''))
laggingreflex 2015年

1
我正在尝试使用angualrjs和webapi2上传50mb pdf文件。我正在使用上面的代码,上传文件后,页面崩溃并挂起。在代码的下面,我使用了webapi方法中的空值。“ var base64String = btoa(String.fromCharCode.apply(null,新的Uint8Array(arrayBuffer)));” 请提出任何想法...
prabhakaran S

2
@Kugel btoa对于代码范围为0-255的字符是安全的,因为这里就是这种情况(想想8 in Uint8Array)。
GOTO

42

对于那些喜欢它的人来说,这是另一种Array.reduce不会引起堆栈溢出的用法:

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

4
不知道这是否真的很性感。毕竟,您正在创建<amount of Bytes in the buffer>新的字符串。
Neonit

怎么btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))
罗伊·廷克

35

还有另一种异步方式使用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"

使用dataurl.split(',', 2)[1]代替dataurl.substr(dataurl.indexOf(',')+1)
卡特·梅德林

这似乎不能保证能正常工作。根据w3c.github.io/FileAPI/#issue-f80bda5b readAsDataURL,理论上可以返回百分比编码的dataURI(而且似乎在jsdom中实际上是这种情况)
TS

@CarterMedlin为什么会splitsubstring呢?
TS

分割更短。但是dataurl可能包含一个或多个逗号(,),分割不安全。
cuixiping

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;
}

不安全。参见@chemoish答案
Kugel

11

我的建议是不要使用本机btoa策略,因为它们不能正确编码所有ArrayBuffer的……

重写atob()和btoa()的DOM

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

尽管我从未遇到过这个确切的错误,但我发现ArrayBuffer我尝试编码的许多编码都不正确。

我会使用MDN建议或要点。


btoa不适用于String,但OP正在询问ArrayBuffer
tsh

1
这非常多,这里有很多片段推荐了错误的内容!我已经多次看到此错误,人们盲目使用atob和btoa。
库格尔

4
应该使用其他答案中的策略对所有数组缓冲区进行正确编码,对于包含大于0xFF的字符(按定义,字节数组不包含)的文本,atob / btoa仅是一个问题。该MDN警告不适用,因为在其他答案中使用该策略时,您可以确保拥有仅包含ASCII字符的字符串,因为Uint8Array中的任何值都可以保证在0到255之间,这意味着可以保证String.fromCharCode返回不超出范围的字符。
Jamesernator

11
var blob = new Blob([arrayBuffer])

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

reader.readAsDataURL(blob);

1
请为您的答案添加一些解释。此代码是什么意思?
奥斯卡


1
这是迄今为止最快的方法-比我的有限测试中的其他方法快几十倍
-jitin

我希望我能像8小时一样再次找到这种解决方案。我的日子不会白白浪费;(谢谢
Kaiser Shahid

7

以下是2个简单的函数,用于将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)));
}

1
这是一个令人困惑的答案。看起来好像不是有效的JavaScript,并且Uint8Array是ArrayBuffer吗?
user1153660

@ user1153660添加function关键字,它应该在现代浏览器中有效。
雪人

太棒了!btoa(String.fromCharCode(... a)); 是到目前为止我见过的用于编码Uint8Array的最短版本。
Nicolo

1
这看起来不错,但如果数组太大,则会抛出最大调用堆栈大小超出错误。
帕维尔Psztyć

0

您可以ArrayBuffer使用从派生普通数组Array.prototype.slice。使用类似Array.prototype.map将字节转换为字符并将join它们一起转换为格式字符串的函数。

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

}

此方法速度更快,因为其中没有运行字符串连接。


不安全。参见@chemoish答案
Kugel

0

OP没有指定运行环境,但是如果您使用的是Node.JS,则有一种非常简单的方法来执行此操作。

与官方Node.JS文档一起进行Accordig 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');

另外,例如,如果您在Angular下运行,则Buffer Class也将在浏览器环境中可用。


您的答案仅适用于NodeJS,不适用于浏览器。
jvatic

1
@jvatic我知道,OP没有明确指定运行环境,因此我的回答并不正确,他只标记了Javascript。因此,我更新了答案以使其更加简洁。我认为这是一个重要的答案,因为我一直在寻找如何执行此操作的方法,而无法找到解决问题的最佳方法。
若昂·爱德华多·苏亚雷斯-席尔瓦

-3

在我身边,使用Chrome导航器,我不得不使用DataView()来读取arrayBuffer

function _arrayBufferToBase64( tabU8A ) {
var binary = '';
let lecteur_de_donnees = new DataView(tabU8A);
var len = lecteur_de_donnees.byteLength;
var chaine = '';
var pos1;
for (var i = 0; i < len; i++) {
    binary += String.fromCharCode( lecteur_de_donnees.getUint8( i ) );
}
chaine = window.btoa( binary )
return chaine;}

-4
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从字符串解压缩归档文件,则更好

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.