如何将uint8数组转换为base64编码字符串?

时间:2012-10-03 13:52:42

标签: javascript base64

我有一个webSocket通信,我收到base64编码的字符串,将其转换为uint8并继续工作,但现在我需要发送回来,我得到了uint8数组,并且需要将其转换为base64字符串,所以我可以发送。 我怎样才能进行这种转换呢?

14 个答案:

答案 0 :(得分:139)

如果您的数据可能包含多字节序列(不是纯ASCII序列)且浏览器有TextDecoder,那么您应该使用它来解码数据(指定TextDecoder所需的编码):

var u8 = new Uint8Array([65, 66, 67, 68]);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(decoder.decode(u8));

如果您需要支持browsers that do not have TextDecoder(目前只是IE和Edge),那么最好的方法是使用TextDecoder polyfill

如果您的数据包含纯ASCII(不是多字节Unicode / UTF-8),那么使用String.fromCharCode的简单替代方法应该得到普遍支持:

var ascii = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(String.fromCharCode.apply(null, ascii));

将base64字符串解码回Uint8Array:

var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) {
    return c.charCodeAt(0); }));

如果您有非常大的数组缓冲区,则apply可能会失败,您可能需要对缓冲区进行分块(基于@RohitSengar发布的缓冲区)。同样,请注意,只有当缓冲区仅包含非多字节ASCII字符时,这才是正确的:

function Uint8ToString(u8a){
  var CHUNK_SZ = 0x8000;
  var c = [];
  for (var i=0; i < u8a.length; i+=CHUNK_SZ) {
    c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ)));
  }
  return c.join("");
}
// Usage
var u8 = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(Uint8ToString(u8));

答案 1 :(得分:16)

function Uint8ToBase64(u8Arr){
  var CHUNK_SIZE = 0x8000; //arbitrary number
  var index = 0;
  var length = u8Arr.length;
  var result = '';
  var slice;
  while (index < length) {
    slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length)); 
    result += String.fromCharCode.apply(null, slice);
    index += CHUNK_SIZE;
  }
  return btoa(result);
}

如果你有一个非常大的Uint8Array,你可以使用这个功能。这是针对Javascript的,在FileReader readAsArrayBuffer的情况下可能很有用。

答案 2 :(得分:15)

非常简单的JavaScript解决方案和测试!

ToBase64 = function (u8) {
    return btoa(String.fromCharCode.apply(null, u8));
}

FromBase64 = function (str) {
    return atob(str).split('').map(function (c) { return c.charCodeAt(0); });
}

var u8 = new Uint8Array(256);
for (var i = 0; i < 256; i++)
    u8[i] = i;

var b64 = ToBase64(u8);
console.debug(b64);
console.debug(FromBase64(b64));

答案 3 :(得分:2)

我将添加另一个适用于不可打印范围的解决方案。我的猜测是,这比链接TextEncoderbtoa更快。

var blob = new Blob( [ uint8ArrayBuffer ], { type: "image/jpeg" } );
var imageUrl = URL.createObjectURL( blob );

这是使用HTML5 API,因此当然不能在Node或其他基于JS的服务器上运行。您可以看到演示here

答案 4 :(得分:2)

使用本机浏览器功能对带有任意数据(不一定是 UTF-8)的 UInt8Array 进行 base64 编码:

const base64_arraybuffer = async (data) => {
    // Use a FileReader to generate a base64 data URI
    const base64url = await new Promise((r) => {
        const reader = new FileReader()
        reader.onload = () => r(reader.result)
        reader.readAsDataURL(new Blob([data]))
    })

    /*
    The result looks like 
    "data:application/octet-stream;base64,<your base64 data>", 
    so we split off the beginning:
    */
    return base64url.split(",", 2)[1]
}

// example use:
await base64_arraybuffer(new UInt8Array([1,2,3,100,200]))

答案 5 :(得分:1)

答案 6 :(得分:1)

这是一个JS函数:

  

该功能是必需的,因为Chrome不接受base64编码的字符串   作为pushManager.subscribe中applicationServerKey的值   https://bugs.chromium.org/p/chromium/issues/detail?id=802280

function urlBase64ToUint8Array(base64String) {
  var padding = '='.repeat((4 - base64String.length % 4) % 4);
  var base64 = (base64String + padding)
    .replace(/\-/g, '+')
    .replace(/_/g, '/');

  var rawData = window.atob(base64);
  var outputArray = new Uint8Array(rawData.length);

  for (var i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

答案 7 :(得分:1)

已经提出的所有解决方案都存在严重问题。一些解决方案无法在大型数组上运行,某些解决方案提供错误的输出,某些解决方案在中间字符串包含多字节字符的情况下在btoa调用上引发错误,有些解决方案消耗的内存超过了所需。

因此,我实现了直接转换功能,该功能无论输入如何都可以正常工作。它每秒可在我的计算机上转换约500万个字节。

https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727

答案 8 :(得分:0)

如果您使用的是Node.js,则可以使用此代码将Uint8Array转换为base64

var b64 = Buffer.from(u8).toString('base64');

答案 9 :(得分:0)

Mozilla Developer Network website显示了一种非常好的解决方法:

function btoaUTF16 (sString) {
    var aUTF16CodeUnits = new Uint16Array(sString.length);
    Array.prototype.forEach.call(aUTF16CodeUnits, function (el, idx, arr) { arr[idx] = sString.charCodeAt(idx); });
    return btoa(String.fromCharCode.apply(null, new Uint8Array(aUTF16CodeUnits.buffer)));
}

function atobUTF16 (sBase64) {
    var sBinaryString = atob(sBase64), aBinaryView = new Uint8Array(sBinaryString.length);
    Array.prototype.forEach.call(aBinaryView, function (el, idx, arr) { arr[idx] = sBinaryString.charCodeAt(idx); });
    return String.fromCharCode.apply(null, new Uint16Array(aBinaryView.buffer));
}

var myString = "☸☹☺☻☼☾☿";

var sUTF16Base64 = btoaUTF16(myString);
console.log(sUTF16Base64);    // Shows "OCY5JjomOyY8Jj4mPyY="

var sDecodedString = atobUTF16(sUTF16Base64);
console.log(sDecodedString);  // Shows "☸☹☺☻☼☾☿"

答案 10 :(得分:0)

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

在以下解决方案中,我省略了对字符串的转换。 IDEA正在关注:

  • 加入3个字节(3个数组元素),您将获得24位
  • 将24位拆分为四个6位数字(值从0到63)
  • 使用该数字作为base64字母的索引
  • corner case:当输入字节数组时 长度不除以3,然后将===添加为结果

以下解决方案适用于3字节的块,因此适用于大型阵列。将base64转换为二进制数组(无atob)的类似解决方案是HERE

function bytesArrToBase64(arr) {
  const abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; // base64 alphabet
  const bin = n => n.toString(2).padStart(8,0); // convert num to 8-bit binary string
  const l = arr.length
  let result = '';

  for(let i=0; i<=(l-1)/3; i++) {
    let c1 = i*3+1>=l; // case when "=" is on end
    let c2 = i*3+2>=l; // case when "=" is on end
    let chunk = bin(arr[3*i]) + bin(c1? 0:arr[3*i+1]) + bin(c2? 0:arr[3*i+2]);
    let r = chunk.match(/.{1,6}/g).map((x,j)=> j==3&&c2 ? '=' :(j==2&&c1 ? '=':abc[+('0b'+x)]));  
    result += r.join('');
  }

  return result;
}


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

let test = "Alice's Adventure in Wondeland.";
let testBytes = [...test].map(c=> c.charCodeAt(0) );

console.log('test string:', test);
console.log('bytes:', JSON.stringify(testBytes));
console.log('btoa            ', btoa(test));
console.log('bytesArrToBase64', bytesArrToBase64(testBytes));

答案 11 :(得分:0)

使用以下命令将uint8数组转换为base64编码的字符串

function arrayBufferToBase64(buffer) {
            var binary = '';
            var bytes = [].slice.call(new Uint8Array(buffer));
            bytes.forEach((b) => binary += String.fromCharCode(b));
            return window.btoa(binary);
        };

答案 12 :(得分:-3)

如果你想要的只是一个base64编码器的JS实现,以便你可以发回数据,你可以尝试btoa函数。

b64enc = btoa(uint);

关于btoa的一些快速说明 - 它是非标准的,因此浏览器不会被迫支持它。 但是,大多数浏览器都有。至少是大的。 atob是相反的转换。

如果您需要不同的实现,或者您发现浏览器不知道您在谈论什么的边缘情况,那么搜索JS的base64编码器并不会太难。

我认为由于某种原因,我公司的网站上有3个人在附近......

答案 13 :(得分:-3)

npm install google-closure-library --save

require("google-closure-library");
goog.require('goog.crypt.base64');

var result =goog.crypt.base64.encodeByteArray(Uint8Array.of(1,83,27,99,102,66));
console.log(result);

$node index.js会将 AVMbY2Y = 写入控制台。