Converte la stringa base64 in ArrayBuffer


98

Ho bisogno di convertire una stringa di codifica base64 in un ArrayBuffer. Le stringhe base64 sono input dell'utente, verranno copiate e incollate da un'e-mail, quindi non sono presenti quando la pagina viene caricata. Vorrei farlo in javascript senza effettuare una chiamata ajax al server, se possibile.

Ho trovato quei link interessanti, ma non mi hanno aiutato:

ArrayBuffer alla stringa con codifica base64

si tratta della conversione opposta, da ArrayBuffer a base64, non il contrario

http://jsperf.com/json-vs-base64/2

sembra buono ma non riesco a capire come usare il codice.

Esiste un modo semplice (forse nativo) per eseguire la conversione? Grazie

Risposte:


147

Prova questo:

function _base64ToArrayBuffer(base64) {
    var binary_string = window.atob(base64);
    var len = binary_string.length;
    var bytes = new Uint8Array(len);
    for (var i = 0; i < len; i++) {
        bytes[i] = binary_string.charCodeAt(i);
    }
    return bytes.buffer;
}

3
Per favore spiegami cosa sta realmente accadendo qui.
Govi S

4
Bene, è abbastanza semplice, prima decodifichiamo la stringa base64 (atob), quindi creiamo un nuovo array di interi senza segno a 8 bit con la stessa lunghezza della stringa decodificata. Dopodiché iteriamo la stringa e popoliamo l'array con il valore Unicode di ogni carattere nella stringa.
Goran.it

2
Da MDN: Base64 è un gruppo di schemi di codifica da binario a testo simili che rappresentano dati binari in un formato di stringa ASCII traducendoli in una rappresentazione radix-64. L'array tipizzato Uint8Array rappresenta un array di interi senza segno a 8 bit e stiamo lavorando con la rappresentazione ASCII dei dati (che è anche una tabella a 8 bit) ..
Goran.it

3
Questo non è corretto. Consente a javascript di interpretare i byte come stringhe, che influiscono sui dati che in realtà sono veri binari.
Tomáš Zato - Ripristina Monica il

4
il problema è che a) non tutte le sequenze di byte sono unicode valide b) non tutti i caratteri in unicode sono un byte, quindi bytes[i] = binary_string.charCodeAt(i);possono essere sbagliati
miscela

52

Utilizzando TypedArray.from :

Uint8Array.from(atob(base64_string), c => c.charCodeAt(0))

Prestazioni da confrontare con la versione for loop della risposta di Goran.it.


2
A chi piace questo tipo di liner, tieni presente che Uint8Array.fromha ancora poca compatibilità con alcuni browser.
IzumiSy

2
Si prega di non consigliare atob o btoa: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
Kugel

il compilatore rails non può gestire questa stringa e fallisce con ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>); (binari 5)
Avael Kross

3
Questo non è un buffer di array. Questo è l'array digitato. Si accede al buffer dell'array tramite la .bufferproprietà di ciò che viene restituito daUint8Array
oligofren

4
@Saites, non c'è niente di sbagliato in atobo btoa, devi solo fornire loro un input valido. atobnecessita di una stringa base64 valida, altrimenti genererà un errore. E btoanecessita di una stringa di byte valida (chiamata anche stringa binaria) che è una stringa contenente caratteri nell'intervallo 0-255. Se la tua stringa ha caratteri al di fuori di tale intervallo, btoaverrà generato un errore.
GetFree

34

La risposta di Goran.it non funziona a causa di un problema unicode in javascript - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding .

Ho finito per utilizzare la funzione data sul blog di Daniel Guerrero: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

La funzione è elencata sul collegamento github: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Usa queste righe

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 

1
Questo metodo è 2 volte più veloce rispetto all'utilizzo di atob.
xiaoyu2er

4
Puoi fare un esempio per il quale non funzionerebbe? L'articolo parla della codifica di stringhe arbitrarie, che potrebbero contenere caratteri Unicode, ma non si applicano atobaffatto.
riv

1
decodeArrayBufferrestituisce un ArrayBufferche ha dimensione sempre divisibile per 3, che non capisco se è di progettazione o un bug. Chiederò nel progetto GitHub.
ceztko

@ceztko Probabilmente è dovuto a un design (accidentale). L'algoritmo di codifica base64 prende gruppi di 3 byte e li trasforma in 4 caratteri. Il metodo di decodifica probabilmente alloca un ArrayBuffer la cui lunghezza è base64String.length / 4 * 3 byte e non tronca mai i byte inutilizzati al termine.
AlwaysLearning

1
@AlwaysLearning, il che significa che probabilmente è disturbato poiché gli zero byte rimanenti potrebbero danneggiare il contenuto di output previsto.
ceztko

21

Ho appena trovato base64-arraybuffer, un piccolo pacchetto npm con un utilizzo incredibilmente elevato, 5 milioni di download il mese scorso (2017-08).

https://www.npmjs.com/package/base64-arraybuffer

Per chiunque cerchi qualcosa della migliore soluzione standard, potrebbe essere questo.


9

Soluzione asincrona , è meglio quando i dati sono grandi:

// base64 to buffer
function base64ToBufferAsync(base64) {
  var dataUrl = "data:application/octet-binary;base64," + base64;

  fetch(dataUrl)
    .then(res => res.arrayBuffer())
    .then(buffer => {
      console.log("base64 to buffer: " + new Uint8Array(buffer));
    })
}

// buffer to base64
function bufferToBase64Async( buffer ) {
    var blob = new Blob([buffer], {type:'application/octet-binary'});    
    console.log("buffer to blob:" + blob)

    var fileReader = new FileReader();
    fileReader.onload = function() {
      var dataUrl = fileReader.result;
      console.log("blob to dataUrl: " + dataUrl);

      var base64 = dataUrl.substr(dataUrl.indexOf(',')+1)      
      console.log("dataUrl to base64: " + base64);
    };
    fileReader.readAsDataURL(blob);
}

6

Javascript è un ottimo ambiente di sviluppo, quindi sembra strano che non fornisca una soluzione a questo piccolo problema. Le soluzioni offerte altrove in questa pagina sono potenzialmente lente. Ecco la mia soluzione. Utilizza la funzionalità incorporata che decodifica gli URL di dati di immagini e suoni in base64.

var req = new XMLHttpRequest;
req.open('GET', "data:application/octet;base64," + base64Data);
req.responseType = 'arraybuffer';
req.onload = function fileLoaded(e)
{
   var byteArray = new Int8Array(e.target.response);
   // var shortArray = new Int16Array(e.target.response);
   // var unsignedShortArray = new Int16Array(e.target.response);
   // etc.
}
req.send();

La richiesta di invio non riesce se la stringa di base 65 è formata male.

Il tipo MIME (application / octet) probabilmente non è necessario.

Testato in cromo. Dovrebbe funzionare in altri browser.


1
Questa era la soluzione perfetta per me, semplice e pulita. L'ho testato rapidamente in Firefox, IE 11, Edge e ha funzionato bene!
cs-NET

non si riferisce alla domanda originale
James Newton

Non sono sicuro di come funzioni per te in IE11, ma ricevo un Access Deniederrore, che sembra essere una limitazione CORS.
Sergiu

6

Per gli utenti di Node.js:

const myBuffer = Buffer.from(someBase64String, 'base64');

myBuffer sarà di tipo Buffer, che è una sottoclasse di Uint8Array. Sfortunatamente, Uint8Array NON è un ArrayBuffer come richiesto dall'OP. Ma quando manipolo un ArrayBuffer lo avvolgo quasi sempre con Uint8Array o qualcosa di simile, quindi dovrebbe essere vicino a ciò che viene richiesto.


2

Pure JS - no string middlestep (no atob)

Scrivo la seguente funzione che converte base64 in modo diretto (senza conversione in stringa al passo medio). IDEA

  • ottenere un blocco di 4 caratteri base64
  • trova l'indice di ogni carattere nell'alfabeto base64
  • converte l'indice in un numero a 6 bit (stringa binaria)
  • unire quattro numeri a 6 bit che danno un numero a 24 bit (memorizzato come stringa binaria)
  • dividere la stringa a 24 bit in tre a 8 bit e convertire ciascuna in un numero e memorizzarle nell'array di output
  • corner case: se la stringa base64 di input termina con uno / due =caratteri, rimuove uno / due numeri dall'array di output

La soluzione sottostante consente di elaborare stringhe base64 di input di grandi dimensioni. Una funzione simile per convertire i byte in base64 senza btoa è QUI


quindi nessun "." mancante?
Gillsoft AB,

Prova in un browser, non sono sicuro che questo sia il risultato atteso? "Alice's Adventure in Wonderland " (ovvero l'ultimo personaggio è NaN)
Gillsoft AB,

1
@GillsoftAB grazie per queste informazioni - hai ragione - risolvo il problema
Kamil Kiełczewski,

-3
const str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
const encoded = new TextEncoder().encode(str) // is Uint8Array
const buf = encoded.buffer // is ArrayBuffer

6
Nota che questo non esegue alcuna decodifica / codifica Base64. Trasforma semplicemente i 6 byte di "base64" in un ArrayBuffer o Uint8Array a 6 elementi.
dubek

2
@dubek è quello che è stato chiesto.
Andrii Nemchenko
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.