Reputation: 1064
I have two functions for converting between Blob
s and arrays of bytes:
function arrayToBlob(data) {
return new Blob(data);
}
function blobToArray(data, callback) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
callback(Array.from(new Uint8Array(reader.result)));
});
reader.readAsArrayBuffer(data);
}
(blobToArray
takes a callback because it requires setting up an event listener.)
I expect these functions to be inverses of each other, but when I run
blobToArray(arrayToBlob([1,2,3]), console.log)
the result I get is not [1, 2, 3]
, but [49, 50, 51]
. Presumably something I'm doing is causing the numbers to be converted to their ASCII values, but I don't know which part is responsible.
Upvotes: 3
Views: 324
Reputation: 7266
The problem is that Blob
's constructor converts numbers in your array to strings. As per MDN documentation Blob
's constructor takes and array of an Array
or ArrayBuffer
, ArrayBufferView
, Blob
, DOMString
objects, or a mix of any of such objects, as a first parameter. All these will be concatenated and put into the Blob
. So each element in the array that you passed is treated on it's own. They are converted to strings (see ASCII table, the code for '1' is 49 and so on) and put into the Blob.
Take note that the results of these 4 expressions are the same:
function arrayToBlob(data) {
return new Blob(data);
}
function blobToArray(data, callback) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
callback(Array.from(new Uint8Array(reader.result)));
});
reader.readAsArrayBuffer(data);
}
blobToArray(arrayToBlob([1,2,3]), console.log)
blobToArray(arrayToBlob(['1','2','3']), console.log)
blobToArray(arrayToBlob([123]), console.log)
blobToArray(arrayToBlob(['123']), console.log)
If you want to get a binary array back you need to pass a propper binary array to the Blob
:
function arrayToBlob(data) {
return new Blob([data]);
}
function blobToArray(data, callback) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
callback(Array.from(new Uint8Array(reader.result)));
});
reader.readAsArrayBuffer(data);
}
var arr = new Uint8Array(3);
arr[0]=1;
arr[1]=2;
arr[2]=3;
blobToArray(arrayToBlob(arr), console.log)
Pay attansion how I pass the Uint8Array
to the Blob
: return new Blob([data]);
. I put it inside an array so it's not get treated as array of objects itself that Blob
takes as 1st parameter.
In conclusion: you did not really do a round trip, you started with one type of array and converted it to another type of array. If you use the propper array from the start then every thing works.
Upvotes: 4
Reputation: 92427
Try this way
function ArrToBlob(arr) {
return new Blob([new Uint8Array(arr)]);
}
async function BlobToArr(blob) {
return [...new Uint8Array(await new Response(blob).arrayBuffer())];
}
async function start() {
let a=[1,2,3];
let b= ArrToBlob(a);
let c = await BlobToArr(b);
let j=JSON.stringify;
console.log('input :',j(a));
console.log('blob :',j(b));
console.log('output:',j(c));
}
start();
Instead of use Uint8Array
you can use e.g. Int32Array
to use negative and bigger numbers than 255 in your array. I also use async/await approach to make code looks more synchronous and less nested (as you can see no explicte callback are used).
Upvotes: 0
Reputation: 6151
A Blob
behaves like a file, I haven't seen anywhere in the documentation that using constructor with an array, elements are trated as text (separate characters), but it seems it does, so the conversion is made at the Blob
construction (note that you don't provide any mime type for the Blob, but in my tests that didn't affect the result of these functions). You can verify with the second function in my example that it does, reading it as text results in a string "123"
.
To be able to see that, i went through some quite extended and interesting article, and the conversion between ArrayBuffer
to Uint8Array
was originally suggested by this SO answer.
Also it seems that to store and retreive values more easily, one can use DataView
, haven't tried but you can find MDN reference here
function arrayToBlob(data) {
return new Blob(data);
}
function blobToArray(data, callback) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
callback( Array.from((new Uint8Array(reader.result)).map(function(a){ return String.fromCharCode(a); })) );
});
reader.readAsArrayBuffer(data);
}
function blobToArrayAsText(data, callback) {
let reader = new FileReader();
reader.addEventListener("loadend", function() {
callback( Array.from(reader.result) ); //result is "123" here
});
reader.readAsText(data);
}
blobToArray(arrayToBlob([1,2,3]), console.log)
blobToArrayAsText(arrayToBlob([1,2,3]), console.log)
Upvotes: 0