Reputation: 604
I am trying to understand how the Blob object can be used to programmatically create binary files on a byte by byte level in client-side javascript. As a way of building up my know how I am trying to create a single byte blob that contains the following octet: 00000001. Simple right? Unfortunately, I haven't been able to figure out how to do so. Below is the first iteration of my code:
let downloadButton = document.getElementById('downloadButton');
downloadButton.addEventListener('click', function(){
var myBlob = new Blob([1], {type : "octet/stream"});
url = window.URL.createObjectURL(myBlob);
let a = document.createElement('A');
a.href = url;
a.download = "testFileOctet";
a.click();
});
I'm not surprised that this doesn't produce the desired bit sequence '00000001' when viewed in a hex editor. I am however surprised that it outputs 00110001 which is the UTF-8 character encoding of '1'. I know that because javascript is weakly typed all numbers are represented as 64-bit floating points so I would have understood if I had a large 64-bit sequence. Or I would have understood if I had specified the MIME type as 'text/plain' instead of 'octet/stream' and had gotten the UTF-8 encoding output.
As it stands, however, I am at a loss... I even attempted some variations where I changed the array being fed into the Blob constructor. Instead of [1] I tried [0x1]. Same result. I tried [0b00000001]. Same result.
So. What am I doing wrong and how is byte-level file creation possible in client-side javascript? Is this a problem with the way I am using the Blob constructor or is it perhaps something to do with the URL encoding that I am using to get the Blob out of the browser? Any help would be much appreciated
Upvotes: 0
Views: 1785
Reputation: 136736
The Blob() constructor expects a possibly mixed list of Blob-parts, ArrayBuffer or USVStrings.
.buffer
property of a TypedArray you would pass in the list. In your case, new Blob([1])
, the Number 1
, being neither a Blob, nor an ArrayBuffer or TypedArray will get coerced to the USVString "1"
.
Just like if you did call new Blob([{}])
, then the literal object would get coerced to the USVString "[object Object]"
.
const obj = new Blob([{}]);
new Response(obj).text().then(v=>console.log('obj', v));
const one = new Blob([1]);
new Response(one).text().then(v=>console.log('one', v));
So how do we set arbitrary bytes?
We use an ArrayBuffer and different views over it.
const buf = new ArrayBuffer(1);
const view = new Uint8Array(buf);
view[0] = 1;
const blob = new Blob([buf]);
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'one.bin';
document.body.append(a);
a.click();
Upvotes: 2