So wechseln Sie von Blob zu ArrayBuffer

110

Ich habe Blobs studiert und festgestellt, dass Sie einen ArrayBuffer wie folgt problemlos in einen Blob konvertieren können:

var dataView = new DataView(arrayBuffer);
var blob = new Blob([dataView], { type: mimeString });

Die Frage, die ich jetzt habe, ist, ob es möglich ist, von einem Blob zu einem ArrayBuffer zu wechseln.

Jeanluca Scaljeri
quelle
2
Blobs sind nicht im nativen JS-Format. Sie sind wie Verweise auf Daten, aber nicht auf die tatsächlichen Daten. Daten von a Blobkönnen nicht direkt gelesen werden, dies kann jedoch mit einigen APIs erfolgen.
Tripulse

Antworten:

39

Die ResponseAPI verwendet eine (unveränderliche), Blobvon der die Daten auf verschiedene Arten abgerufen werden können. Das OP hat nur darum gebeten ArrayBuffer, und hier ist eine Demonstration davon.

var blob = GetABlobSomehow();

// NOTE: you will need to wrap this up in a async block first.
/* Use the await keyword to wait for the Promise to resolve */
await new Response(blob).arrayBuffer();   //=> <ArrayBuffer>

alternativ können Sie dies verwenden:

new Response(blob).arrayBuffer()
.then(/* <function> */);

Hinweis: Diese API ist nicht mit älteren ( alten ) Browsern kompatibel. Schauen Sie sich daher zur Sicherheit die Browserkompatibilitätstabelle an.

Tripulse
quelle
1
Dies sollte die Top-Antwort IMO sein.
Cameron Martin
const arrayBuffer = warte auf neue Antwort (blob) .arrayBuffer ();
R.Cha
1
@ R.Cha Danke für das Update. Das habe ich nicht bemerkt!
Tripulse
2
Cleverer Trick und nicht zu verwechseln, Blob.arrayBuffer()der selbst im Jahr 2020 eine recht schlechte Kompatibilität aufweist: caniuse.com/#feat=mdn-api_blob_arraybuffer oder developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer
jpschroeder
Was ist die Leistung davon? Kopiert es die Daten in den Blob oder gibt es nur eine Ansicht davon zurück?
GaryO
141

Sie können FileReaderdas Blobals lesen ArrayBuffer.

Hier ist ein kurzes Beispiel:

var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

Hier ist ein längeres Beispiel:

// ArrayBuffer -> Blob
var uint8Array  = new Uint8Array([1, 2, 3]);
var arrayBuffer = uint8Array.buffer;
var blob        = new Blob([arrayBuffer]);

// Blob -> ArrayBuffer
var uint8ArrayNew  = null;
var arrayBufferNew = null;
var fileReader     = new FileReader();
fileReader.onload  = function(event) {
    arrayBufferNew = event.target.result;
    uint8ArrayNew  = new Uint8Array(arrayBufferNew);

    // warn if read values are not the same as the original values
    // arrayEqual from: http://stackoverflow.com/questions/3115982/how-to-check-javascript-array-equals
    function arrayEqual(a, b) { return !(a<b || b<a); };
    if (arrayBufferNew.byteLength !== arrayBuffer.byteLength) // should be 3
        console.warn("ArrayBuffer byteLength does not match");
    if (arrayEqual(uint8ArrayNew, uint8Array) !== true) // should be [1,2,3]
        console.warn("Uint8Array does not match");
};
fileReader.readAsArrayBuffer(blob);
fileReader.result; // also accessible this way once the blob has been read

Dies wurde in der Konsole von Chrome 27—69, Firefox 20—60 und Safari 6—11 getestet.

Hier ist auch eine Live-Demonstration, mit der Sie spielen können: https://jsfiddle.net/potatosalad/FbaM6/

Update 2018-06-23: Danke an Klaus Klein für den Tipp über event.target.resultversusthis.result

Referenz:

Kartoffelsalat
quelle
22
scheint das nicht viel Code zu sein ... für etwas, das einfach sein sollte?
Henley Chiu
2
@ HenleyChiu Ich habe die Antwort so bearbeitet, dass sie eine kurze Version des Codes enthält. Das längere Beispiel soll vollständig in sich geschlossen sein (zeigt, wie der ArrayBuffer, der Blob und wieder zurück erstellt werden). Ich konnte keinen synchronen Weg zum Lesen eines Blobs finden, ohne einen Web Worker und FileReaderSync zu verwenden .
Potatosalad
1
Einige Leute wollen wirklich beweisen, dass die Rückrufhölle existiert. Es ist sinnvoll für GROSSE Blobs, aber für normale Anwendungsfälle sollte JavaScript eine Synchronisierungsmethode bereitstellen.
Lama12345
das war sehr nützlich
Jimmy Obonyo Abor
@ Anuj Du hast falsch gemacht. Es sollte sich nicht darauf beziehen this. <EventTarget>.resultsollte das beheben!
Tripulse
17

Nur um die Antwort von Herrn @potatosalad zu ergänzen.

Sie nicht wirklich brauchen , um die Funktion für den Zugriff auf Umfang das Ergebnis auf dem bekommen onload Rückruf, können Sie die folgende auf den frei machen Ereignisparameter:

var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function(event) {
    arrayBuffer = event.target.result;
};
fileReader.readAsArrayBuffer(blob);

Warum ist das besser? Denn dann können wir die Pfeilfunktion verwenden, ohne den Kontext zu verlieren

var fileReader = new FileReader();
fileReader.onload = (event) => {
    this.externalScopeVariable = event.target.result;
};
fileReader.readAsArrayBuffer(blob);
Klaus Klein
quelle
15

Oder Sie können die Abruf-API verwenden

fetch(URL.createObjectURL(myBlob)).then(res => res.arrayBuffer())

Ich weiß nicht, was der Leistungsunterschied ist, und dies wird auch auf Ihrer Netzwerkregisterkarte in DevTools angezeigt.

Arlen Beiler
quelle
17
Oder einfachnew Response(blob).arrayBuffer()
Endless
4

Es gibt jetzt (Chrome 76+ & FF 69+) eine Blob.prototype.arrayBuffer () -Methode, die ein Versprechen zurückgibt, das mit einem ArrayBuffer aufgelöst wird, der die Daten des Blobs darstellt.

(async () => {
  const blob = new Blob(['hello']);
  const buf = await blob.arrayBuffer();
  console.log( buf.byteLength ); // 5
})();

Kaiido
quelle
2
Leider funktioniert derzeit nicht in Safari (noch)
HerrZatacke