[javascript] uint8 배열을 base64 인코딩 문자열로 변환하는 방법은 무엇입니까?

webSocket 통신이 있고 base64로 인코딩 된 문자열을 받아서 uint8로 변환하여 작업하지만 이제 다시 보내야하고 uint8 배열을 가져 와서 base64 문자열로 변환해야하므로 보낼 수 있습니다. 이 변환을 어떻게 할 수 있습니까?



답변

이미 제안 된 모든 솔루션에는 심각한 문제가 있습니다. 일부 솔루션은 대형 배열에서 작동하지 않고 일부는 잘못된 출력을 제공하며 일부는 중간 문자열에 멀티 바이트 문자가 포함 된 경우 btoa 호출에 오류가 발생하고 일부는 필요한 것보다 더 많은 메모리를 소비합니다.

그래서 입력에 관계없이 작동하는 직접 변환 기능을 구현했습니다. 내 컴퓨터에서 초당 약 5 백만 바이트를 변환합니다.

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


답변

데이터에 다중 바이트 시퀀스 (일반 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 polyfill 을 사용하는 입니다.

데이터에 일반 ASCII (멀티 바이트 유니 코드 / 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));


답변

매우 간단한 솔루션과 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));


답변

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의 경우 유용 할 수 있습니다.


답변

Node.js를 사용하는 경우이 코드를 사용하여 Uint8Array를 base64로 변환 할 수 있습니다.

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


답변

여기에 JS 함수가 있습니다.

Chrome은 아직 pushManager.subscribe의 applicationServerKey 값으로 base64로 인코딩 된 문자열을 허용하지 않기 때문에이 함수가 필요합니다.
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;
}


답변

순수 JS-문자열 중간 단계 없음 (btoa 없음)

아래 솔루션에서는 문자열로의 변환을 생략합니다. IDEA는 다음과 같습니다.

  • 3 바이트 (3 개의 배열 요소)를 결합하면 24 비트가됩니다.
  • 24 비트를 4 개의 6 비트 숫자로 분할 (0에서 63까지의 값 사용)
  • 그 숫자를 base64 알파벳의 색인으로 사용하십시오.
  • 코너 케이스 : 입력 바이트 배열의 길이가 3으로 나뉘 지 않은 경우 추가 =또는 ==결과

아래 솔루션은 3 바이트 청크에서 작동하므로 큰 배열에 적합합니다. base64를 이진 배열로 변환하는 유사한 솔루션 (없음 atob)이 여기 있습니다.