Comment passer de Blob à ArrayBuffer

111

J'étudiais les Blobs et j'ai remarqué que lorsque vous avez un ArrayBuffer, vous pouvez facilement le convertir en Blob comme suit:

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

La question que je me pose maintenant est la suivante: est-il possible de passer d'un Blob à un ArrayBuffer?

Jeanluca Scaljeri
la source
2
Les objets blob ne sont pas au format JS natif. Ce sont comme des références à des données mais pas aux données réelles. Les données d'un Blobne peuvent pas être lues directement, mais cela pourrait être fait avec certaines API.
tripulse

Réponses:

39

L' ResponseAPI consomme un (immuable) à Blobpartir duquel les données peuvent être récupérées de plusieurs manières. L' OP a seulement demandé ArrayBuffer, et en voici une démonstration.

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>

vous pouvez également utiliser ceci:

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

Remarque: cette API n'est pas compatible avec les navigateurs plus anciens ( anciens ), alors jetez un œil au tableau de compatibilité des navigateurs pour être sûr;)

tripulse
la source
1
Cela devrait être la meilleure réponse de l'OMI.
Cameron Martin
const arrayBuffer = attendre une nouvelle réponse (blob) .arrayBuffer ();
R.Cha
1
@ R.Cha Merci pour le correctif. Je n'ai pas remarqué ça!
tripulse
2
Astuce intelligente et à ne pas confondre avec Blob.arrayBuffer()qui a en fait une compatibilité assez médiocre même en 2020, caniuse.com/#feat=mdn-api_blob_arraybuffer ou developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer
jpschroeder
Quelle est la performance de cela? Copie-t-il les données dans le blob ou renvoie-t-il simplement une vue de celui-ci?
GaryO le
141

Vous pouvez utiliser FileReaderpour lire le Blobsous forme de fichier ArrayBuffer.

Voici un petit exemple:

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

Voici un exemple plus long:

// 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

Cela a été testé dans la console de Chrome 27—69, Firefox 20—60 et Safari 6—11.

Voici également une démonstration en direct avec laquelle vous pouvez jouer: https://jsfiddle.net/potatosalad/FbaM6/

Mise à jour 23/06/2018: Merci à Klaus Klein pour le conseil sur event.target.resultversusthis.result

Référence:

salade de pommes de terre
la source
23
cela ne semble-t-il pas beaucoup de code ... pour quelque chose qui devrait être simple?
Henley Chiu
3
@HenleyChiu J'ai modifié la réponse pour inclure une version courte du code. L'exemple le plus long est destiné à être entièrement autonome (montre comment créer le ArrayBuffer, le Blob et inversement). Je n'ai pas été en mesure de trouver un moyen synchrone de lire un objet blob sans utiliser de Web Worker et FileReaderSync .
potatosalad
1
Certaines personnes veulent vraiment prouver que l'enfer du rappel existe. Cela a du sens pour les BLOB LARGE, mais pour les cas d'utilisation normaux, JavaScript doit fournir une méthode de synchronisation.
lama12345
c'était très utile
Jimmy Obonyo Abor
@Anuj Vous avez mal fait. Cela ne devrait pas faire référence this. <EventTarget>.resultdevrait réparer ça!
tripulse
17

Juste pour compléter la réponse de M. @potatosalad.

Vous n'avez pas réellement besoin d'accéder à la portée de la fonction pour obtenir le résultat du rappel onload , vous pouvez effectuer librement les opérations suivantes sur le paramètre d' événement :

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

Pourquoi c'est mieux? Parce qu'alors nous pouvons utiliser la fonction de flèche sans perdre le contexte

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

Ou vous pouvez utiliser l'API fetch

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

Je ne sais pas quelle est la différence de performances, et cela apparaîtra également sur votre onglet réseau dans DevTools.

Arlen Beiler
la source
17
Ou justenew Response(blob).arrayBuffer()
Endless
4

Il existe maintenant (Chrome 76+ et FF 69+) une méthode Blob.prototype.arrayBuffer () qui retournera une promesse résolue avec un ArrayBuffer représentant les données du Blob.

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

Kaiido
la source
2
Malheureusement actuellement ne fonctionne pas dans Safari (encore)
HerrZatacke