将base64字符串转换为ArrayBuffer

Ton*_*ony 75 javascript base64 arraybuffer

我需要将base64编码字符串转换为ArrayBuffer.base64字符串是用户输入,它们将从电子邮件中复制和粘贴,因此在加载页面时它们不存在.如果可能的话,我想在javascript中执行此操作而不对服务器进行ajax调用.

我发现这些链接很有趣,但他们没有帮助我:

ArrayBuffer到base64编码的字符串

这是相反的转换,从ArrayBuffer到base64,而不是相反

http://jsperf.com/json-vs-base64/2

这看起来不错,但我无法弄清楚如何使用代码.

是否有一种简单的(可能是原生的)方式进行转换?谢谢

Gor*_*.it 116

试试这个:

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)

  • 请给我解释一下什么是真正发生在这里. (3认同)
  • 好吧,它非常简单,首先我们解码base64字符串(atob),然后我们创建新的8位无符号整数数组,其长度与解码后的字符串相同.之后,我们迭代字符串并使用字符串中每个字符的Unicode值填充数组. (3认同)
  • 问题是a)并非每个字节序列都是有效的unicode b)并非unicode中的每个字符都是一个字节,因此“ bytes [i] = binary_string.charCodeAt(i);”可能是错误的 (3认同)
  • 来自MDN:Base64是一组类似的二进制文本编码方案,通过将其转换为基数-64表示,以ASCII字符串格式表示二进制数据.Uint8Array类型数组表示一个8位无符号整数数组,我们正在处理数据的ASCII表示(也是一个8位表). (2认同)
  • 这是不正确的。它允许javascript将字节解释为字符串,从而影响实际上是真正二进制的数据。 (2认同)
  • 这个答案是正确的,我已经测试了所有可能的值。函数“window.atob”对输入进行解码,然后将每个解码后的字节写入 2 个字节的 UTF-16 字符中。不会有任何丢失,因为一个字节最多只能达到 255。请注意,如果编码内容是 UTF-8 文本,您仍然需要对其进行解码: `new TextDecoder("utf-8").decode(_base64ToArrayBuffer(" 4oKs"));`。 (2认同)

ofa*_*vre 42

使用TypedArray.from:

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))
Run Code Online (Sandbox Code Playgroud)

性能与Goran.it的for循环版本进行比较.

  • @Saites,“atob”或“btoa”没有任何问题,您只需为它们提供有效的输入即可。`atob` 需要一个有效的 base64 字符串,否则会抛出错误。而 `btoa` 需要一个有效的字节字符串(也称为二进制字符串),它是包含 0-255 范围内的字符的字符串。如果您的字符串包含超出该范围的字符,“btoa”将抛出错误。 (8认同)
  • 对于喜欢这种衬板的人,请记住,`Uint8Array.from`仍然与某些浏览器不兼容。 (2认同)
  • 请不要推荐 atob 或 btoa:https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding (2认同)
  • 这不是数组缓冲区。这是类型化数组。您可以通过Uint8Array返回的.buffer属性访问数组缓冲区。 (2认同)

Yaa*_*aan 27

由于javascript中的unicode问题,Goran.it的答案无效 - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding.

我最终使用了Daniel Guerrero博客上提供的功能:http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

函数列在github链接:https ://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

使用这些行

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 
Run Code Online (Sandbox Code Playgroud)

  • 您能举一个无法解决的例子吗?本文讨论编码任意字符串,其中可能包含unicode字符,但根本不适用于`atob`。 (2认同)
  • `decodeArrayBuffer` 返回一个大小总是可以被 3 整除的 `ArrayBuffer`,我不明白这是设计还是错误。我会在github项目中问。 (2认同)
  • @AlwaysLearning 这意味着它可能有问题,因为剩余的零字节可能会破坏预期的输出内容。 (2认同)

Doo*_*ber 20

对于 Node.js 用户:

const myBuffer = Buffer.from(someBase64String, 'base64');
Run Code Online (Sandbox Code Playgroud)

myBuffer 将是 Buffer 类型,它是 Uint8Array 的子类。不幸的是, Uint8Array 不是 OP 要求的 ArrayBuffer。但是在操作 ArrayBuffer 时,我几乎总是用 Uint8Array 或类似的东西包装它,所以它应该接近所要求的。

  • 这实际上似乎并没有产生“Uint8Array”,因为代码期望在传递此调用的结果时出现错误。但是,“Uint8Array.from(Buffer.from(someBase64String, 'base64'))”非常适合生成“Uint8Array”类型值。 (8认同)

jv-*_*dev 15

刚刚找到base64-arraybuffer,一个小的npm软件包,使用率极高,上个月下载量为500万(2017-08).

https://www.npmjs.com/package/base64-arraybuffer

对于那些寻找最佳标准解决方案的人来说,可能就是这样.


张浩然*_*张浩然 13

异步解决方案,数据大时更好:

// base64 to buffer
function base64ToBufferAsync(base64) {
  var dataUrl = "data:application/octet-binary;base64," + base64;

  fetch(dataUrl)
    .then(res => res.arrayBuffer())
    .then(buffer => {
      console.log("base64 to buffer: " + new Uint8Array(buffer));
    })
}

// buffer to base64
function bufferToBase64Async( buffer ) {
    var blob = new Blob([buffer], {type:'application/octet-binary'});    
    console.log("buffer to blob:" + blob)

    var fileReader = new FileReader();
    fileReader.onload = function() {
      var dataUrl = fileReader.result;
      console.log("blob to dataUrl: " + dataUrl);

      var base64 = dataUrl.substr(dataUrl.indexOf(',')+1)      
      console.log("dataUrl to base64: " + base64);
    };
    fileReader.readAsDataURL(blob);
}
Run Code Online (Sandbox Code Playgroud)


Kam*_*ski 11

纯 JS - 无字符串中间步骤(无 atob)

我编写了以下函数,该函数以直接方式转换 Base64(中间步骤无需转换为字符串)。主意

  • 获取4个base64字符块
  • 查找 Base64 字母表中每个字符的索引
  • 将索引转换为 6 位数字(二进制​​字符串)
  • 连接四个 6 位数字,得到 24 位数字(存储为二进制字符串)
  • 将 24 位字符串拆分为三个 8 位字符串,并将每个字符串转换为数字并将它们存储在输出数组中
  • 极端情况:如果输入的 base64 字符串以一/两个=字符结尾,则从输出数组中删除一/两个数字

下面的解决方案允许处理大型输入 base64 字符串。类似的将字节转换为 base64 而不使用 btoa 的函数在这里

function base64ToBytesArr(str) {
  const abc = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"]; // base64 alphabet
  let result = [];

  for(let i=0; i<str.length/4; i++) {
    let chunk = [...str.slice(4*i,4*i+4)]
    let bin = chunk.map(x=> abc.indexOf(x).toString(2).padStart(6,0)).join(''); 
    let bytes = bin.match(/.{1,8}/g).map(x=> +('0b'+x));
    result.push(...bytes.slice(0,3 - (str[4*i+2]=="=") - (str[4*i+3]=="=")));
  }
  return result;
}


// --------
// TEST
// --------


let test = "Alice's Adventure in Wonderland.";  

console.log('test string:', test.length, test);
let b64_btoa = btoa(test);
console.log('encoded string:', b64_btoa);

let decodedBytes = base64ToBytesArr(b64_btoa); // decode base64 to array of bytes
console.log('decoded bytes:', JSON.stringify(decodedBytes));
let decodedTest = decodedBytes.map(b => String.fromCharCode(b) ).join``;
console.log('Uint8Array', JSON.stringify(new Uint8Array(decodedBytes)));
console.log('decoded string:', decodedTest.length, decodedTest);
Run Code Online (Sandbox Code Playgroud)

警告!

如果您想将 base64 解码为 STRING(不是字节数组)并且您知道结果包含 utf8 字符,那么通常atob失败atob("8J+SqQ=="),例如对于字符,会给出错误的结果。在这种情况下,您可以使用上述解决方案并以正确的方式将结果字节数组转换为字符串,例如:

function base64ToBytesArr(str) {
  const abc = [..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"]; // base64 alphabet
  let result = [];

  for(let i=0; i<str.length/4; i++) {
    let chunk = [...str.slice(4*i,4*i+4)]
    let bin = chunk.map(x=> abc.indexOf(x).toString(2).padStart(6,0)).join(''); 
    let bytes = bin.match(/.{1,8}/g).map(x=> +('0b'+x));
    result.push(...bytes.slice(0,3 - (str[4*i+2]=="=") - (str[4*i+3]=="=")));
  }
  return result;
}


// --------
// TEST
// --------


let testB64 = "8J+SqQ==";   // for string: "";  
console.log('input base64            :', testB64);

let decodedBytes = base64ToBytesArr(testB64); // decode base64 to array of bytes
console.log('decoded bytes           :', JSON.stringify(decodedBytes));

let result = new TextDecoder("utf-8").decode(new Uint8Array(decodedBytes));
console.log('properly decoded string :', result);

let result_atob = atob(testB64);
console.log('decoded by atob         :', result_atob);
Run Code Online (Sandbox Code Playgroud)

片段于 2022 年 8 月 4 日在以下平台上进行测试:chrome 103.0.5060.134 (arm64)、safari 15.2、firefox 103.0.1 (64 位)、edge 103.0.1264.77 (arm64) 和node-js v12.16.1


小智 7

Javascript 是一个很好的开发环境,所以它似乎很奇怪,因为它没有为这个小问题提供解决方案。本页其他地方提供的解决方案可能很慢。这是我的解决方案。它采用内置功能来解码 base64 图像和声音数据 url。

var req = new XMLHttpRequest;
req.open('GET', "data:application/octet;base64," + base64Data);
req.responseType = 'arraybuffer';
req.onload = function fileLoaded(e)
{
   var byteArray = new Uint8Array(e.target.response);
   // var shortArray = new Int16Array(e.target.response);
   // var unsignedShortArray = new Int16Array(e.target.response);
   // etc.
}
req.send();
Run Code Online (Sandbox Code Playgroud)

如果 base 64 字符串格式错误,则发送请求将失败。

mime 类型(应用程序/八位字节)可能是不必要的。

在铬中测试。应该在其他浏览器中工作。

  • 这可以更简洁地写为带有 async/await 和 Fetch API 的 `await (await fetch("data:application/octet;base64," + base64data)).arrayBuffer()`。 (7认同)
  • 这对我来说是完美的解决方案,简单干净。我很快在 Firefox、IE 11、Edge 中进行了测试,效果很好! (2认同)