webSocket通信を取得し、base64でエンコードされた文字列を受信し、それをuint8に変換して作業しますが、送信する必要があります。uint8配列を取得し、base64文字列に変換して送信できるようにします。どうすればこの変換を行うことができますか?
webSocket通信を取得し、base64でエンコードされた文字列を受信し、それをuint8に変換して作業しますが、送信する必要があります。uint8配列を取得し、base64文字列に変換して送信できるようにします。どうすればこの変換を行うことができますか?
回答:
すでに提案されているすべてのソリューションには深刻な問題があります。大きな配列で機能しないソリューション、間違った出力を提供するソリューション、中間文字列にマルチバイト文字が含まれている場合にbtoa呼び出しでエラーをスローするソリューション、必要以上のメモリを消費するソリューションがあります。
そこで、入力に関係なく機能する直接変換関数を実装しました。それは私のマシンで毎秒約500万バイトを変換します。
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ポリフィルを使用することです。
データにプレーン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));
btoa(String.fromCharCode.apply(null, myArray))
Uint8Array
。128..255の範囲のバイトがある場合、テキストデコーダーが誤ってそれらをユニコード文字に変換し、base64コンバーターが機能しなくなるTextDecoder
ため、ここで使用するのは絶対に間違ってUint8Array
います。
非常にシンプルなソリューションと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
Node.jsを使用している場合は、このコードを使用してUint8Arrayをbase64に変換できます
var b64 = Buffer.from(u8).toString('base64');
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用であり、FileReaderreadAsArrayBufferの場合に役立ちます。
String.fromCharCode.apply()
メソッドはUTF-8を再現できません:UTF-8文字の長さは1バイトから4バイトまで変化する可能性がありますがString.fromCharCode.apply()
、UInt8のセグメントでUInt8Arrayを検査するため、各文字が正確に1バイトの長さであり、隣接する文字から独立していると誤って想定しますもの。入力UInt8Arrayでエンコードされた文字がすべてASCII(シングルバイト)範囲にある場合、偶然に機能しますが、完全なUTF-8を再現することはできません。そのためには、TextDecoderまたは同様のアルゴリズムが必要です。
これに対する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文字列をUnicodeをサポートするUint8ArrayまたはArrayBufferにデコードします)
必要なのが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
。