Konvertieren Sie den base64-String in ArrayBuffer

94

Ich muss eine Base64-Codierungszeichenfolge in einen ArrayBuffer konvertieren. Die base64-Zeichenfolgen sind Benutzereingaben. Sie werden aus einer E-Mail kopiert und eingefügt, sodass sie beim Laden der Seite nicht vorhanden sind. Ich möchte dies in Javascript tun, ohne wenn möglich einen Ajax-Aufruf an den Server zu senden.

Ich fand diese Links interessant, aber sie haben mir nicht geholfen:

ArrayBuffer zu Base64-codierter Zeichenfolge

Hierbei handelt es sich um die entgegengesetzte Konvertierung von ArrayBuffer zu base64, nicht umgekehrt

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

Das sieht gut aus, aber ich kann nicht herausfinden, wie man den Code benutzt.

Gibt es eine einfache (möglicherweise native) Möglichkeit, die Konvertierung durchzuführen? Vielen Dank

Tony
quelle

Antworten:

141

Versuche dies:

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;
}
Goran.it
quelle
3
Bitte erklären Sie mir, was hier wirklich passiert.
Govinda Sakhare
4
Nun, es ist ziemlich einfach. Zuerst dekodieren wir den base64-String (atob), dann erstellen wir ein neues Array von 8-Bit-Ganzzahlen ohne Vorzeichen mit der gleichen Länge wie der decodierte String. Danach iterieren wir die Zeichenfolge und füllen das Array mit dem Unicode-Wert jedes Zeichens in der Zeichenfolge.
Goran.it
2
Von MDN: Base64 ist eine Gruppe ähnlicher Binär-Text-Codierungsschemata, die Binärdaten in einem ASCII-Zeichenfolgenformat darstellen, indem sie in eine Radix-64-Darstellung übersetzt werden. Das vom Typ Uint8Array typisierte Array repräsentiert ein Array von 8-Bit-Ganzzahlen ohne Vorzeichen, und wir arbeiten mit der ASCII-Darstellung der Daten (die auch eine 8-Bit-Tabelle ist).
Goran.it
3
Das ist nicht richtig. Es ermöglicht Javascript, Bytes als Zeichenfolge zu interpretieren, was sich auf Daten auswirkt, die tatsächlich binär sind.
Tomáš Zato - Wiedereinsetzung Monica
4
Das Problem ist, dass a) nicht jede Byte-Sequenz Unicode gültig ist b) Nicht jedes Zeichen im Unicode ist ein Byte, bytes[i] = binary_string.charCodeAt(i);kann also falsch sein
Mischung
50

Verwenden von TypedArray.from :

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

Die Leistung muss mit der for-Loop-Version der Goran.it-Antwort verglichen werden.

ofavre
quelle
2
Wer diese Art von Liner mag, sollte bedenken, dass er Uint8Array.frommit einigen Browsern nur wenig kompatibel ist.
IzumiSy
2
Bitte empfehlen Sie nicht atob oder btoa: developer.mozilla.org/en-US/docs/Web/API/WindowBase64/…
Kugel
Der Rails-Compiler kann diesen String nicht verarbeiten und schlägt mit fehl ExecJS::RuntimeError: SyntaxError: Unexpected token: operator (>). (Schienen 5)
Avael Kross
3
Dies ist kein Array-Puffer. Dies ist das typisierte Array. Sie erhalten Zugriff auf den Array-Puffer über die .bufferEigenschaft, was vonUint8Array
Oligofren
3
@ Saites, es ist nichts falsch mit atoboder btoa, Sie müssen ihnen nur gültige Eingaben geben. atobbenötigt eine gültige base64-Zeichenfolge, andernfalls wird ein Fehler ausgegeben. Und btoabenötigt eine gültige Byte-Zeichenfolge (auch als binäre Zeichenfolge bezeichnet), die Zeichenfolgen im Bereich von 0 bis 255 enthält. Wenn Ihre Zeichenfolge Zeichen außerhalb dieses Bereichs enthält, btoawird ein Fehler ausgegeben.
GetFree
32

Die Antwort von Goran.it funktioniert aufgrund eines Unicode-Problems in Javascript nicht - https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding .

Am Ende habe ich die Funktion von Daniel Guerreros Blog verwendet: http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/

Die Funktion ist unter dem Github-Link aufgeführt: https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js

Verwenden Sie diese Zeilen

var uintArray = Base64Binary.decode(base64_string);  
var byteArray = Base64Binary.decodeArrayBuffer(base64_string); 
Yaan
quelle
1
Diese Methode ist 2x schneller als die Verwendung von atob.
Xiaoyu2er
4
Können Sie ein Beispiel geben, für das es nicht funktionieren würde? Der Artikel befasst sich mit der Codierung beliebiger Zeichenfolgen, die möglicherweise Unicode-Zeichen enthalten, jedoch überhaupt nicht gelten atob.
Riv
1
decodeArrayBufferGibt eine zurück ArrayBuffer, deren Größe immer durch 3 teilbar ist, was ich nicht verstehe, wenn es beabsichtigt ist oder ein Fehler vorliegt. Ich werde im Github-Projekt fragen.
Ceztko
@ceztko Es ist wahrscheinlich (versehentlich) beabsichtigt. Der Base64-Codierungsalgorithmus verwendet Gruppen von 3 Bytes und wandelt sie in 4 Zeichen um. Die Decodierungsmethode weist wahrscheinlich einen ArrayBuffer zu, dessen Länge base64String.length / 4 * 3 Bytes beträgt, und schneidet nach Abschluss keine nicht verwendeten Bytes mehr ab.
AlwaysLearning
1
@AlwaysLearning, was bedeutet, dass es wahrscheinlich fehlerhaft ist, da übrig gebliebene Null-Bytes den beabsichtigten Ausgabeinhalt beschädigen können.
Ceztko
21

Ich habe gerade base64-arraybuffer gefunden, ein kleines npm-Paket mit unglaublich hoher Auslastung, 5 Millionen Downloads im letzten Monat (2017-08).

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

Für alle, die nach einer der besten Standardlösungen suchen, ist dies möglicherweise die richtige Lösung.

jv-dev
quelle
9

Asynchrone Lösung, es ist besser, wenn die Daten groß sind:

// 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);
}
张浩然
quelle
6

Für Node.js Benutzer:

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

myBuffer ist vom Typ Buffer, einer Unterklasse von Uint8Array. Leider ist Uint8Array KEIN ArrayBuffer, wie es das OP verlangt hat. Aber wenn ich einen ArrayBuffer manipuliere, verpacke ich ihn fast immer mit Uint8Array oder ähnlichem, daher sollte er nahe an dem liegen, wonach gefragt wird.

DoomGoober
quelle
5

Javascript ist eine gute Entwicklungsumgebung, daher scheint es seltsam, als würde es keine Lösung für dieses kleine Problem bieten. Die an anderer Stelle auf dieser Seite angebotenen Lösungen sind möglicherweise langsam. Hier ist meine Lösung. Es verwendet die integrierte Funktionalität, die Base64-Bild- und Sounddaten-URLs dekodiert.

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();

Die Sendeanforderung schlägt fehl, wenn die Zeichenfolge der Basis 65 schlecht gebildet ist.

Der MIME-Typ (Anwendung / Oktett) ist wahrscheinlich nicht erforderlich.

In Chrom getestet. Sollte in anderen Browsern funktionieren.

Dinosaurierklee
quelle
1
Dies war die perfekte Lösung für mich, einfach und sauber. Ich habe es schnell in Firefox, IE 11, Edge getestet und gut funktioniert!
CS-NET
bezieht sich nicht auf die ursprüngliche Frage
James Newton
Ich bin nicht sicher, wie es für Sie in IE11 funktioniert, aber ich erhalte eine Access DeniedFehlermeldung, die eine CORS-Einschränkung zu sein scheint.
Sergiu
2

Pure JS - kein String-Mittelschritt (kein Atob)

Ich schreibe folgende Funktion, die base64 direkt konvertiert (ohne Konvertierung in einen String im mittleren Schritt). IDEE

  • Holen Sie sich 4 Base64 Zeichen Chunk
  • Finden Sie den Index jedes Zeichens im base64-Alphabet
  • Index in 6-Bit-Zahl konvertieren (Binärzeichenfolge)
  • Verbinden Sie vier 6-Bit-Zahlen, die eine 24-Bit-Zahl ergeben (als Binärzeichenfolge gespeichert).
  • Teilen Sie die 24-Bit-Zeichenfolge in drei 8-Bit-Zeichenfolgen auf und verdecken Sie jede, um sie zu nummerieren und im Ausgabearray zu speichern
  • Eckfall: Wenn die Eingabe Base64-Zeichenfolge mit einem / zwei Zeichen endet =, entfernen Sie eine / zwei Zahlen aus dem Ausgabearray

Die folgende Lösung ermöglicht die Verarbeitung großer Base64-Eingabezeichenfolgen. Eine ähnliche Funktion zum Konvertieren von Bytes in base64 ohne btoa gibt es HIER

Kamil Kiełczewski
quelle
also kein fehlendes "."?
Gillsoft AB
In einem Browser testen, bin ich mir nicht sicher, ob dies das erwartete Ergebnis ist? "Alice im Wunderland" (dh der letzte Charakter ist NaN)
Gillsoft AB
1
@ GilloftAB danke für diese Info - Sie haben Recht - ich
behebe
-3
const str = "dGhpcyBpcyBiYXNlNjQgc3RyaW5n"
const encoded = new TextEncoder().encode(str) // is Uint8Array
const buf = encoded.buffer // is ArrayBuffer
Andrii Nemchenko
quelle
6
Beachten Sie, dass hierdurch keine Base64-Decodierung / -Codierung durchgeführt wird. Es verwandelt nur die 6 Bytes von "base64" in einen ArrayBuffer mit 6 Elementen oder Uint8Array.
Dubek
2
@dubek das wurde gefragt.
Andrii Nemchenko