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
)이 여기 있습니다.