147

I was studying Blobs, and I noticed that when you have an ArrayBuffer, you can easily convert this to a Blob as follows:

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

The question I have now is, is it possible to go from a Blob to an ArrayBuffer?

1
  • 5
    Blobs aren't in native JS format. They're like references to data but not the actual data. Data from a Blob cannot be directly read but it could be done with some APIs. Commented Jun 26, 2019 at 1:39

7 Answers 7

162

You can use FileReader to read the Blob as an ArrayBuffer.

Here's a short example:

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

Here's a longer example:

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

This was tested out in the console of Chrome 27—69, Firefox 20—60, and Safari 6—11.

Here's also a live demonstration which you can play with: https://jsfiddle.net/potatosalad/FbaM6/

Update 2018-06-23: Thanks to Klaus Klein for the tip about event.target.result versus this.result

Reference:

Sign up to request clarification or add additional context in comments.

4 Comments

doesn't this seem like a lot of code.. for something that should be simple?
@HenleyChiu I edited the answer to include a short version of the code. The longer example is intended to be fully self-contained (shows how to create the ArrayBuffer, the Blob, and back again). I haven't been able to find a synchronous way to read a Blob without using a Web Worker and FileReaderSync.
Some people really want to prove the callback hell exists. It makes sense for LARGE blobs, but for normal use cases JavaScript should provide a sync method.
FYI await blob.arrayBuffer() has good support now: developer.mozilla.org/en-US/docs/Web/API/Blob/…
77

The Response API consumes a (immutable) Blob from which the data can be retrieved in several ways. The OP only asked for ArrayBuffer, and here's a demonstration of it.

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 */
const arrayBuffer = await new Response(blob).arrayBuffer();

Alternatively you could use this:

new Response(blob).arrayBuffer().then((arrayBuffer) => {
 // do something with the arrayBuffer
});

Note: This API isn't compatible with older (ancient) browsers so take a look to the Browser Compatibility Table to be on the safe side ;)

5 Comments

Clever trick and not to be confused with Blob.arrayBuffer() which actually has quite poor compatibility even in 2020, caniuse.com/#feat=mdn-api_blob_arraybuffer or developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer
What's the performance of this? Does it copy the data in the Blob or just return a view of it?
@GaryO Haven't benchmarked it, I assume it copies the blob and returns a view over it.
Sigh, it appears it does copy. That's bad if the blob is big!
FYI await blob.arrayBuffer() has good support now: developer.mozilla.org/en-US/docs/Web/API/Blob/…
22

Or you can use the fetch API

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

I don't know what the performance difference is, and this will show up on your network tab in DevTools as well.

2 Comments

Or just new Response(blob).arrayBuffer()
Or await blob.arrayBuffer() which now has good support: developer.mozilla.org/en-US/docs/Web/API/Blob/…
18

Just to complement Mr @potatosalad answer.

You don't actually need to access the function scope to get the result on the onload callback, you can freely do the following on the event parameter:

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

Why this is better? Because then we may use arrow function without losing the context

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

Comments

13

There is now (Chrome 76+ & FF 69+) a Blob.prototype.arrayBuffer() method which will return a Promise resolving with an ArrayBuffer representing the Blob's data.

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

3 Comments

Unfortunately currently does not work in Safari (yet)
@HerrZatacke, see my answer
According to developer.mozilla.org/en-US/docs/Web/API/Blob/… Safari supports this API with version 14+.
12

This is an async method which first checks for the availability of arrayBuffer method. This function is backward compatible and future proof.

async function blobToArrayBuffer(blob) {
    if ('arrayBuffer' in blob) return await blob.arrayBuffer();
    
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onload = () => resolve(reader.result);
        reader.onerror = () => reject();
        reader.readAsArrayBuffer(blob);
    });
}

2 Comments

It seems to be a wrong answer since the return value of reader.onerror cannot be a function. so it should be like the following. reader.onerror = (e) => reject(e) or reader.onerror = reject
I had to move readAsArrayBuffer before the onload/onerror declarations for my unit tests to run.
10

await blob.arrayBuffer() is good.

The problem is when iOS / Safari support is needed.. for that  one would need this:

Blob.prototype.arrayBuffer ??=function(){ return new Response(this).arrayBuffer() }

4 Comments

stackoverflow.com/a/51758200/3702797 and all the other fallbacks are already there.
@Kaiido, See stackoverflow.com/questions/15341912/…. My method is superior and is required until iOS support. (after which the line can simply be removed)
And a FileReader is still needed in IE. My point is that your answer doesn't offer anything more than what the previous answers gave. If one wants to build a polyfill, all the various ways of doing the same task are already there.
@Kaiido, IE requirements are rare. ¶ Yep, this is the only answer with the polyfill.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.