webSocket 통신이 있고 base64로 인코딩 된 문자열을 받아서 uint8로 변환하여 작업하지만 이제 다시 보내야하고 uint8 배열을 가져 와서 base64 문자열로 변환해야하므로 보낼 수 있습니다. 이 변환을 어떻게 할 수 있습니까?
답변:
이미 제안 된 모든 솔루션에는 심각한 문제가 있습니다. 일부 솔루션은 대형 배열에서 작동하지 않고 일부는 잘못된 출력을 제공하며 일부는 중간 문자열에 멀티 바이트 문자가 포함 된 경우 btoa 호출에 오류가 발생하고 일부는 필요한 것보다 더 많은 메모리를 소비합니다.
그래서 입력에 관계없이 작동하는 직접 변환 기능을 구현했습니다. 내 컴퓨터에서 초당 약 5 백만 바이트를 변환합니다.
https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
"ABCDEFG..."
?
데이터에 다중 바이트 시퀀스 (일반 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));
btoa(String.fromCharCode.apply(null, myArray))
Uint8Array
. 128..255 범위의 바이트가 TextDecoder
있으면 Uint8Array
텍스트 디코더가이를 유니 코드 문자로 잘못 변환하여 base64 변환기를 손상 시키므로 여기서 사용하는 것은 절대적으로 잘못된 것 입니다.
매우 간단한 솔루션과 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));
RangeError: Maximum call stack size exceeded
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의 경우 유용 할 수 있습니다.
String.fromCharCode.apply()
메서드는 UTF-8을 재현 할 수 없습니다. UTF-8 문자의 길이는 1 바이트에서 4 바이트까지 다양 할 수 있지만 String.fromCharCode.apply()
UInt8의 세그먼트에서 UInt8Array를 검사하므로 각 문자의 길이가 정확히 1 바이트이고 인접 문자와 독립적이라고 잘못 가정합니다. 하나. 입력 UInt8Array에 인코딩 된 문자가 모두 ASCII (단일 바이트) 범위에 있으면 우연히 작동하지만 전체 UTF-8을 재현 할 수는 없습니다. TextDecoder 또는 이와 유사한 알고리즘이 필요합니다.
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;
}
아래 솔루션에서는 문자열로의 변환을 생략합니다. IDEA는 다음과 같습니다.
=
또는 ==
결과아래 솔루션은 3 바이트 청크에서 작동하므로 큰 배열에 적합합니다. base64를 이진 배열로 변환하는 유사한 솔루션 (없음 atob
)이 여기 있습니다.
다음을 사용하여 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);
};
(유니 코드 지원을 사용하여 Base64 문자열을 Uint8Array 또는 ArrayBuffer로 디코딩)
이에 대한 매우 좋은 접근 방식은 Mozilla 개발자 네트워크 웹 사이트에 나와 있습니다 .
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 "☸☹☺☻☼☾☿"
원하는 것은 base64 인코더의 JS 구현뿐이므로 데이터를 다시 보낼 수 있습니다 btoa
. 함수를 사용해 볼 수 있습니다 .
b64enc = btoa(uint);
btoa에 대한 몇 가지 간단한 참고 사항-비표준이므로 브라우저가이를 지원하도록 강요하지 않습니다. 그러나 대부분의 브라우저는 그렇습니다. 적어도 큰 것. atob
반대의 변환입니다.
다른 구현이 필요하거나 브라우저가 당신이 무슨 말을하는지 알지 못하는 엣지 케이스를 발견한다면 JS 용 base64 인코더를 찾는 것은 그리 어렵지 않을 것입니다.
제 회사 웹 사이트에 왠지 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을 콘솔에.
-ve
높은 답변이 아닌 투표 된 답변이 받아 들여지는 것은 재밌습니다 +ve
.