HTML5 Filesystem API: downloading a sandboxed file?
Asked Answered
A

0

6

I have some data in indexeddb files, and I'd like to allow my users to download that data to import into other applications. I can use Blobs to do this easily:

 var blob = new Blob(['herp!'], {type: 'application/octet-stream'});
 var iframe = document.createElement("iframe");
 iframe.id = "myiframe";
 iframe.style.display = "none";
 iframe.src = window.webkitURL.createObjectURL(blob); // needs a revokeObjectURL
 $('#dlplaceholder').append(iframe);

The correct type parameter to Blob is key: if I set it to text/plain, it won't download the file. If I have the iframe a height and width and a display type of block, I can see the data in the iframe.

However, I'll want to build one file out of multiple values from my database, and each of those values can be large, and I can have a lot of entries. I can concatenate those values in the Blob constructor, but I'm worried about having so much data in memory that I blow up.

So I decided to create a file in the sandboxed system and append each value to it, and use the file instead of the blob as the argument to createObjectURL. But when I do that, it doesn't download; it behaves exactly as if I had used my Blob code with a type of text/plain. Here's the code:

var fname = 'mybadtest'; //UPDATE here's the problem: needs .bin file extension
var init_fs = function ( fs ) {
  // first, write to the sandboxed file
  fs.root.getFile(fname, {create: true, exclusive: true}, function(fileEntry) {
    fileEntry.createWriter(function(fileWriter) {
      fileWriter.onwriteend = function(e) {
        // write to file completed. now use the file for download
        fs.root.getFile(fname, {}, function(fileEntry) {
          fileEntry.file(function(file) {
            var iframe = document.createElement("iframe");
            iframe.id = "myiframe";
            iframe.style.display = "none";
            iframe.src = window.webkitURL.createObjectURL(file) // needs revokeObjURL                                        
            $('#dlplaceholder').append(iframe);
          }, errorHandler);
        }, errorHandler);
     };
     var blob = new Blob(['derp!'], {type: 'application/octet-stream'});
     fileWriter.write(blob);
   }, errorHandler);
  }, errorHandler);
};

window.webkitStorageInfo.requestQuota(PERSISTENT, mysz, function(grantedBytes) {
  window.webkitRequestFileSystem(PERSISTENT, grantedBytes, init_fs, errorHandler);
}, err_function );

If I give the iframe a size and set the display to block, I can see the data I wrote to the file. So I know I got the file writing part right.

Any ideas on how I can give the file the right type so I can download it? I've been through the MDN docs, the HTML5 Rocks tuts, and Eric Bidelman's "Using the Filesystem API" book, but I don't see anything that addresses this situation. I'm using Chrome version 27.0.1453.110.

UPDATE: problem solved; see comment below.

UPDATED UPDATE: see Rob W's useful comment about an alternate approach below.

Argyrol answered 8/6, 2013 at 3:47 Comment(3)
It turns out that all I needed to do is use a file extension that's recognized as an octet-stream MIME type, and the download will happen. So, naming the sandboxed file 'foo.bin' will work, a just plain 'foo' won't.Argyrol
That sounds like an awful solution. Have you already considered using the download attribute of an anchor? Supported by Chrome and Firefox (20?).Mccourt
Rob, that worked nicely -- thanks for the suggestion. Bonus: I get to set the filename to something reasonable.Argyrol

© 2022 - 2024 — McMap. All rights reserved.