Как преобразовать массив uint8 в base64 Encoded String?

У меня есть связь с webSocket, я получаю кодировку base64, конвертирую ее в uint8 и работаю над ней, но теперь мне нужно отправить обратно, я получил массив uint8 и мне нужно преобразовать его в base64 string, поэтому я могу Отправь это. Как я могу сделать это преобразование?

Ответ 1

Все предложенные решения имеют серьезные проблемы. Некоторые решения не работают на больших массивах, некоторые выдают неправильный вывод, некоторые выдают ошибку при вызове btoa, если промежуточная строка содержит многобайтовые символы, другие потребляют больше памяти, чем необходимо.

Поэтому я реализовал функцию прямого преобразования, которая просто работает независимо от ввода. Он конвертирует около 5 миллионов байт в секунду на моей машине.

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

Ответ 2

Если ваши данные могут содержать многобайтовые последовательности (а не обычную последовательность ASCII), и в вашем браузере есть TextDecoder, то вы должны использовать это для декодирования ваших данных (укажите необходимую кодировку для TextDecoder):

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

Если вам необходимо поддерживать браузеры, в которых нет TextDecoder (в настоящее время это только IE и Edge), тогда лучшим вариантом будет использование полизаполнения TextDecoder.

Если ваши данные содержат простой 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); }));

Если у вас очень большие буферы массива, тогда может произойти сбой применения, и вам может потребоваться разбить буфер на части (основанный на том, который был опубликован @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));

Ответ 3

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.

Ответ 4

Очень простое решение и тест для 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));

Ответ 5

ОБНОВЛЕНИЕ 2019: Я рассмотрел это, и это не решение для отправки изображений, а только отображать их локально. createObjectURL создает не данные base64, а DOMString, который представляет собой просто короткий специфичный для браузера URL-адрес, который можно использовать в img.src или аналогичном.


Я добавлю другое решение, которое работает с непечатаемыми диапазонами. Это намного быстрее, чем связывание TextEncoder и btoa, когда все, что вам нужно, это отобразить изображение, полученное в виде байтового массива.

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

Это использует API-интерфейсы HTML5 и поэтому, конечно, не будет работать на Node или других серверах на основе JS. Вы можете увидеть демо здесь.

Ответ 7

Вот функция JS для этого:

Эта функция необходима, поскольку Chrome не принимает строку в кодировке base64 в качестве значения для applicationServerKey в pushManager.subscribe 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;
}

Ответ 8

Если вы используете Node.js, то вы можете использовать этот код для преобразования Uint8Array в base64

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

Ответ 9

Я попробовал несколько подходов, но если я попытаюсь загрузить более 20 МБ более или менее, Iexplorer взорвется. недостаточно памяти

какие-либо предложения?

Ответ 10

Если вы хотите использовать JS-реализацию base64-encoder, чтобы вы могли отправить данные назад, вы можете попробовать функцию btoa.

b64enc = btoa(uint);

Несколько быстрых заметок на btoa - это нестандартное, поэтому браузеры не вынуждены его поддерживать. Однако большинство браузеров. Большие, по крайней мере. atob - противоположное преобразование.

Если вам нужна другая реализация или вы найдете краткий случай, когда браузер не знает, о чем вы говорите, поиск кодера base64 для JS не будет слишком сложным.

Я думаю, что есть 3 из них, висящих на моем веб-сайте компании, почему-то...

Ответ 11

npm установить 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 = в консоль.