Ho una comunicazione webSocket, ricevo una stringa codificata base64, la converto in uint8 e ci lavoro, ma ora devo rispedire, ho ricevuto l'array uint8 e devo convertirlo in stringa base64, quindi posso inviarlo. Come posso fare questa conversione?
Ho una comunicazione webSocket, ricevo una stringa codificata base64, la converto in uint8 e ci lavoro, ma ora devo rispedire, ho ricevuto l'array uint8 e devo convertirlo in stringa base64, quindi posso inviarlo. Come posso fare questa conversione?
Risposte:
Tutte le soluzioni già proposte presentano gravi problemi. Alcune soluzioni non funzionano su array di grandi dimensioni, alcune forniscono un output errato, alcune generano un errore sulla chiamata btoa se una stringa intermedia contiene caratteri multibyte, altre consumano più memoria del necessario.
Quindi ho implementato una funzione di conversione diretta che funziona indipendentemente dall'input. Converte circa 5 milioni di byte al secondo sulla mia macchina.
https://gist.github.com/enepomnyaschih/72c423f727d395eeaa09697058238727
"ABCDEFG..."
?
Se i tuoi dati possono contenere sequenze multibyte (non una semplice sequenza ASCII) e il tuo browser ha TextDecoder , allora dovresti usarlo per decodificare i tuoi dati (specifica la codifica richiesta per TextDecoder):
var u8 = new Uint8Array([65, 66, 67, 68]);
var decoder = new TextDecoder('utf8');
var b64encoded = btoa(decoder.decode(u8));
Se è necessario supportare browser che non dispongono di TextDecoder (attualmente solo IE ed Edge), l'opzione migliore è utilizzare un polyfill TextDecoder .
Se i tuoi dati contengono un semplice ASCII (non multibyte Unicode / UTF-8), allora c'è una semplice alternativa String.fromCharCode
che dovrebbe essere abbastanza universalmente supportata:
var ascii = new Uint8Array([65, 66, 67, 68]);
var b64encoded = btoa(String.fromCharCode.apply(null, ascii));
E per decodificare la stringa base64 in un Uint8Array:
var u8_2 = new Uint8Array(atob(b64encoded).split("").map(function(c) {
return c.charCodeAt(0); }));
Se si dispone di buffer di array molto grandi, l'applicazione potrebbe non riuscire e potrebbe essere necessario suddividere in blocchi il buffer (in base a quello pubblicato da @RohitSengar). Di nuovo, nota che questo è corretto solo se il tuo buffer contiene solo caratteri ASCII non multibyte:
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
. TextDecoder
è assolutamente la cosa sbagliata da usare qui, perché se il tuo Uint8Array
ha byte nell'intervallo 128..255, il decodificatore di testo li convertirà erroneamente in caratteri Unicode, il che interromperà il convertitore base64.
Soluzione molto semplice e test per 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
Se stai usando Node.js, puoi usare questo codice per convertire Uint8Array in 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);
}
È possibile utilizzare questa funzione se si dispone di un Uint8Array molto grande. Questo è per Javascript, può essere utile in caso di FileReader readAsArrayBuffer.
String.fromCharCode.apply()
metodi @ Jens non possono riprodurre UTF-8: i caratteri UTF-8 possono variare in lunghezza da un byte a quattro byte, tuttavia String.fromCharCode.apply()
esamina un UInt8Array in segmenti di UInt8, quindi presume erroneamente che ogni carattere sia esattamente lungo un byte e indipendente dal vicino quelli. Se i caratteri codificati nell'input UInt8Array si trovano tutti nell'intervallo ASCII (byte singolo), funzionerà per caso, ma non può riprodurre UTF-8 completo. Hai bisogno di TextDecoder o di un algoritmo simile per questo.
Ecco una funzione JS per questo:
Questa funzione è necessaria perché Chrome non accetta una stringa con codifica base64 come valore per applicationServerKey in pushManager.subscribe ancora 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;
}
Nella soluzione sotto ometto la conversione in stringa. IDEA sta seguendo:
=
o ==
al risultatoLa soluzione seguente funziona su blocchi di 3 byte, quindi è utile per array di grandi dimensioni. Una soluzione simile per convertire base64 in array binario (senza atob
) è QUI
Utilizzare quanto segue per convertire l'array uint8 in una stringa con codifica base64
function arrayBufferToBase64(buffer) {
var binary = '';
var bytes = [].slice.call(new Uint8Array(buffer));
bytes.forEach((b) => binary += String.fromCharCode(b));
return window.btoa(binary);
};
(Decodifica una stringa Base64 in Uint8Array o ArrayBuffer con supporto Unicode)
Se tutto ciò che desideri è un'implementazione JS di un codificatore base64, in modo da poter restituire i dati, puoi provare la btoa
funzione.
b64enc = btoa(uint);
Un paio di brevi note su btoa: non è standard, quindi i browser non sono obbligati a supportarlo. Tuttavia, la maggior parte dei browser lo fa. Almeno quelli grandi. atob
è la conversione opposta.
Se hai bisogno di un'implementazione diversa, o trovi un caso limite in cui il browser non ha idea di cosa stai parlando, cercare un codificatore base64 per JS non sarebbe troppo difficile.
Penso che ce ne siano 3 in giro sul sito web della mia azienda, per qualche motivo ...
npm installa google-closing-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
scriverebbe AVMbY2Y = sulla console.
-ve
risposta votata sia accettata piuttosto che altamente +ve
.