155

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

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

ArrayBuffer 到 base64 编码的字符串

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

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

这看起来不错,但我不知道如何使用代码。

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

4

12 回答 12

205

尝试这个:

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;
}
于 2014-02-15T12:12:17.867 回答
91

使用TypedArray.from

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

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

于 2016-12-12T17:33:09.157 回答
41

由于 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); 
于 2016-04-02T21:26:09.970 回答
29

对于 Node.js 用户:

const myBuffer = Buffer.from(someBase64String, 'base64');

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

于 2020-04-09T22:47:34.397 回答
28

刚刚发现 base64-arraybuffer,一个使用率非常高的小型 npm 包,上个月(2017-08)下载了 500 万次。

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

对于任何寻找最佳标准解决方案的人来说,这可能就是它。

于 2017-05-18T18:10:56.553 回答
17

异步解决方案,数据大的时候比较好:

// 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);
}
于 2019-01-10T06:50:45.220 回答
10

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();

如果 base 64 字符串格式不正确,则发送请求将失败。

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

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

于 2018-03-14T08:48:20.673 回答
4

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

我编写了以下函数,它以直接方式转换 base64(在中间步骤不转换为字符串)。主意

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

下面的解决方案允许处理大型输入 base64 字符串。在没有 btoa 的情况下将字节转换为 base64 的类似功能是HERE

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

于 2020-06-13T19:13:41.980 回答
3

我强烈建议使用正确实现 base64 规范的 npm 包。

我知道的最好的是rfc4648

问题是 btoa 和 atob 使用二进制字符串而不是 Uint8Array 并且尝试与它相互转换很麻烦。在 npm 中也有很多不好的包。在找到那个之前我浪费了很多时间。

该特定包的创建者做了一件简单的事情:他们采用 Base64 的规范(顺便提一下)并从头到尾正确实现它。(包括规范中也有用的其他格式,如 Base64-url、Base32 等......)这似乎并不多,但显然这对其他库来说太过分了。

所以是的,我知道我正在做一些传教,但如果你想避免浪费你的时间,只需使用 rfc4648。

于 2020-12-11T08:22:36.107 回答
0

atob 的结果是一个用逗号分隔的字符串

,

一种更简单的方法是将此字符串转换为 json 数组字符串,然后将其解析为 byteArray 下面的代码可以简单地用于将 base64 转换为数字数组

let byteArray = JSON.parse('['+atob(base64)+']'); 
let buffer = new Uint8Array(byteArray);
于 2021-09-11T16:10:01.947 回答
0

我使用这个问题的公认答案在通过 ASCII-cookie [atob, btoa are base64[with +/]<->js binary string] 传输的 base64Url 数据领域中创建 base64Url string <-> arrayBuffer 转换,所以我决定发布代码。

我们中的许多人可能想要转换,并且客户端-服务器通信可能使用 base64Url 版本(尽管如果我理解得很好,cookie 可能包含 +/ 和 -_ 字符,只有 ",;\ 字符和 128 ASCII 中的一些邪恶字符是不允许的)。但是 url 不能包含 / 字符,因此更广泛地使用 b64 url​​ 版本,这当然不是 atob-btoa 支持的......

看到其他评论,我想强调一下,我的用例是通过 url/cookie 传输 base64Url 数据,并尝试将此加密数据与 js crypto api (2017) 一起使用,因此需要 ArrayBuffer 表示和 b64u <-> arrBuff 转换...如果数组缓冲区表示 base64(ascii 的一部分)以外的内容,则此转换将不起作用,因为 atob,btoa 仅限于 ascii(128)。查看合适的转换器,如下所示:

buff -> b64u 版本来自 Mathias Bynens 的推文,(也)感谢那个!他还写了一个base64编码器/解码器: https ://github.com/mathiasbynens/base64

来自 java,在尝试理解 java byte[] 实际上是 js Int8Array (signed int) 的代码时可能会有所帮助,但我们在这里使用无符号版本 Uint8Array,因为 js 转换适用于它们。它们都是256位的,所以我们现在在js中称之为byte[]...

代码来自模块类,这就是为什么是静态的。

//utility

/**
 * Array buffer to base64Url string
 * - arrBuff->byte[]->biStr->b64->b64u
 * @param arrayBuffer
 * @returns {string}
 * @private
 */
static _arrayBufferToBase64Url(arrayBuffer) {
    console.log('base64Url from array buffer:', arrayBuffer);

    let base64Url = window.btoa(String.fromCodePoint(...new Uint8Array(arrayBuffer)));
    base64Url = base64Url.replaceAll('+', '-');
    base64Url = base64Url.replaceAll('/', '_');

    console.log('base64Url:', base64Url);
    return base64Url;
}

/**
 * Base64Url string to array buffer
 * - b64u->b64->biStr->byte[]->arrBuff
 * @param base64Url
 * @returns {ArrayBufferLike}
 * @private
 */
static _base64UrlToArrayBuffer(base64Url) {
    console.log('array buffer from base64Url:', base64Url);

    let base64 = base64Url.replaceAll('-', '+');
    base64 = base64.replaceAll('_', '/');
    const binaryString = window.atob(base64);
    const length = binaryString.length;
    const bytes = new Uint8Array(length);
    for (let i = 0; i < length; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }

    console.log('array buffer:', bytes.buffer);
    return bytes.buffer;
}
于 2022-02-17T18:14:08.927 回答
-6
let str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
let encoded = new TextEncoder().encode(str) // is Uint8Array
let buf = encoded.buffer // is ArrayBuffer
于 2018-05-30T13:08:43.483 回答