ArrayBuffer 到 base64 编码的字符串
Posted
技术标签:
【中文标题】ArrayBuffer 到 base64 编码的字符串【英文标题】:ArrayBuffer to base64 encoded string 【发布时间】:2012-03-05 06:58:13 【问题描述】:我需要一种有效的(读取本机)方法将ArrayBuffer
转换为需要在多部分帖子中使用的 base64 字符串。
【问题讨论】:
【参考方案1】: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
【讨论】:
我尝试了链接中的非本地实现,转换一个 1M 大小的缓冲区需要 1 分半钟,而上面的循环代码只需要 1 秒。 我喜欢这种方法的简单性,但所有字符串连接都可能代价高昂。看起来在 Firefox、IE 和 Safari 上构建一个字符数组并在最后join()
ing 他们明显更快(但在 Chrome 上慢得多):jsperf.com/tobase64-implementations
我正在尝试使用 angualrjs 和 webapi2 上传 50mb 的 pdf 文件。我正在使用上面的代码,上传文件后,页面崩溃并挂起。下面的代码行,我被使用但在 webapi 方法中获取空值。 “var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));”请提出任何想法...
我想知道为什么每个人都避免使用本机缓冲区toString('base64')
方法。
@JoãoEduardoSoareseSilva 因为不是每个人都在使用 Node - Node 的 Buffer
在浏览器中不存在。【参考方案2】:
这对我来说很好用:
var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
在 ES6 中,语法稍微简单一些:
const base64String = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
正如 cmets 中所指出的,当ArrayBuffer
很大时,此方法可能会在某些浏览器中导致运行时错误。在任何情况下,确切的大小限制都取决于实现。
【讨论】:
为了简洁起见,我更喜欢这种方法,但会出现“超出最大调用堆栈大小错误”。上面的循环技术解决了这个问题。 我也遇到了堆栈大小错误,所以我使用了 mobz 的答案,效果很好。 它不适用于大缓冲区。稍作修改使其工作:btoa([].reduce.call(new Uint8Array(bufferArray),function(p,c)return p+String.fromCharCode(c),''))
我正在尝试使用 angualrjs 和 webapi2 上传 50mb 的 pdf 文件。我正在使用上面的代码,上传文件后,页面崩溃并挂起。下面的代码行,我被使用但在 webapi 方法中得到空值。 “var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));”请提出任何想法...
@Kugel btoa
对于代码范围 0-255 中的字符是安全的,因为这里就是这种情况(想想Uint8Array
中的 8)。【参考方案3】:
对于喜欢简短的人来说,这是另一个使用Array.reduce
不会导致堆栈溢出的:
var base64 = btoa(
new Uint8Array(arrayBuffer)
.reduce((data, byte) => data + String.fromCharCode(byte), '')
);
【讨论】:
不确定这是否真的很性感。毕竟,您正在创建<amount of Bytes in the buffer>
新字符串。
btoa(new Uint8Array(arraybuffer).reduce((data,byte)=>(data.push(String.fromCharCode(byte)),data),[]).join(''))
怎么样?
另一种选择:btoa(Array.from(new Uint8Array(arraybuffer)).map(b => String.fromCharCode(b)).join(''))
.
在 'Window' 上执行 'btoa' 失败:要编码的字符串包含 Latin1 范围之外的字符【参考方案4】:
还有另一种异步方式使用 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-f80bda5breadAsDataURL
理论上可以返回一个百分比编码的dataURI(看起来jsdom实际上是这种情况)
@CarterMedlin 为什么split
会比substring
更好?
分割更短。但是dataurl可能包含一个或多个逗号(,),拆分是不安全的。【参考方案5】:
var blob = new Blob([arrayBuffer])
var reader = new FileReader();
reader.onload = function(event)
var base64 = event.target.result
;
reader.readAsDataURL(blob);
【讨论】:
请为您的答案添加一些解释。这段代码是什么意思? 类似helpful MDN example。 这是迄今为止最快的方法 - 在我有限的测试中比其他方法快几十倍 我希望我能像 8 小时一样再次找到这个解决方案。我的一天不会被浪费;(谢谢 我认为您还需要删除 DataURL 标头 (data:*/*;base64,
) 才能仅获取 Base64 字符串。见MDN docs【参考方案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;
【讨论】:
不安全。见@chemoish 答案 这是我发现的唯一对我有用的解决方案。【参考方案7】:我的建议是不要使用原生 btoa
策略,因为它们不能正确编码所有 ArrayBuffer
的...
rewrite the DOMs atob() and btoa()
由于 DOMStrings 是 16 位编码的字符串,在大多数浏览器中,如果字符超出 8 位 ASCII 编码字符的范围,则对 Unicode 字符串调用 window.btoa 会导致字符超出范围异常。
虽然我从未遇到过这个确切的错误,但我发现我尝试编码的许多 ArrayBuffer
编码不正确。
我会使用 MDN 推荐或要点。
https://github.com/beatgammit/base64-js https://gist.github.com/jonleighton/958841【讨论】:
btoa
不适用于字符串,但 OP 正在询问 ArrayBuffer
。
非常这个,这里这么多sn-ps推荐错了!我多次看到这个错误,人们盲目地使用 atob 和 btoa。
所有数组缓冲区都应使用其他答案中的策略进行良好编码,atob/btoa 仅对包含大于 0xFF 的字符的文本存在问题(根据定义,字节数组不存在)。 MDN 警告不适用,因为在其他答案中使用该策略时,您可以保证有一个仅由 ASCII 字符组成的字符串,因为 Uint8Array 中的任何值都保证在 0 到 255 之间,这意味着保证 String.fromCharCode返回一个不超出范围的字符。
这是当 btoa 或 Buffer 不可用时的正确答案(react-native)【参考方案8】:
下面是 2 个简单的函数,用于将 Uint8Array 转换为 Base64 字符串并再次返回
arrayToBase64String(a)
return btoa(String.fromCharCode(...a));
base64StringToArray(s)
let asciiString = atob(s);
return new Uint8Array([...asciiString].map(char => char.charCodeAt(0)));
【讨论】:
这是一个令人困惑的答案。这看起来不像是有效的 javascript,Uint8Array 是 ArrayBuffer 吗? @user1153660 添加function
关键字,它应该可以在现代浏览器中使用。
太棒了! btoa(String.fromCharCode(...a));是迄今为止我见过的对 Uint8Array 进行编码的最短版本。
这看起来不错,但如果数组太大,则会抛出超出最大调用堆栈大小的错误。【参考方案9】:
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');
此外,例如,如果您在 Angular 下运行,缓冲区类也将在浏览器环境中可用。
【讨论】:
你的回答只适用于NodeJS,在浏览器中不起作用。 @jvatic 我明白了,OP没有明确指定运行环境,所以我的回答没有错误,他只标记了Javascript
。所以我更新了我的答案以使其更简洁。我认为这是一个重要的答案,因为我一直在寻找如何做到这一点,但无法找到问题的最佳答案。【参考方案10】:
如果您可以添加库,base64-arraybuffer:
yarn add base64-arraybuffer
然后:
encode(buffer)
- 将 ArrayBuffer 编码为 base64 字符串
decode(str)
- 将 base64 字符串解码为 ArrayBuffer
【讨论】:
对我来说最好的答案,因为包括解码【参考方案11】:您可以使用Array.prototype.slice
从ArrayBuffer
派生一个普通数组。
使用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 答案【参考方案12】:在浏览器和Node.js中使用uint8-to-b64
包进行编码/解码
【讨论】:
【参考方案13】:在我身边,使用 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;
【讨论】:
【参考方案14】: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 从字符串中解压存档,这样会更好
【讨论】:
以上是关于ArrayBuffer 到 base64 编码的字符串的主要内容,如果未能解决你的问题,请参考以下文章
uniapp解决图形验证码问题及arraybuffer二进制转base64格式图片