Skip to content Skip to sidebar Skip to footer

Copy File From Addon To Profile Folder

I'm trying to copy a sqlite database from the data folder in my extension directory, to the profile folder, in order to use it. So for now, I'm trying with that: const {Cc, Ci, Cu}

Solution 1:

Besides that it uses sync I/O (opening the channel with .open instead of .asyncOpen), the NetUtil.asyncCopy operation is still async, meaning the code

NetUtil.asyncCopy(istream, ostream, function(aResult) {
  console.log(aResult); // return 0
})

console.log(FileUtils.getFile("ProfD", ["searchEngines.sqlite"]).exists()); // return falselet dbConn = Services.storage.openDatabase(file);

will try to open the file before the copy likely finishes! However, file.exists() will be likely true, because you already opened the file for writing. It's just that the file is still blank because the data copy isn't done (or even started) yet. (Actually, it is true, because you're checking searchEngines.sqlite in ProfD and not TmpD, but if you correct that the previous statement would apply).

You can only use the file when/after your callback to .asyncCopy is done, e.g.

NetUtil.asyncCopy(istream, ostream, function(aResult) {
  console.log(aResult);
  console.log(FileUtils.getFile("ProfD", ["searchEngines.sqlite"]).exists()); // return falselet dbConn = Services.storage.openDatabase(file);
  // ...
});

PS: You might want to .asyncOpen the channel, then use NetUtil.asyncFetch and pass the resulting stream to .asyncCopy to be truly async for smallish files, since this caches the contents in memory first.

For large files you could create a variant of the NetUtil.asyncFetch implementation that feeds the .outputStream end directly to NetUtils.asyncCopy. That is a bit more complicated, so I won't be writing this up in detail until somebody is truly interested in this and ask the corresponding question.

Edit, so here is how I'd write it:

const data = require('sdk/self').data;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");

functioncopyDataURLToFile(url, file, callback) {
  NetUtil.asyncFetch(url, function(istream) {
    var ostream = Cc["@mozilla.org/network/file-output-stream;1"].
                  createInstance(Ci.nsIFileOutputStream);
    ostream.init(file, -1, -1, Ci.nsIFileOutputStream.DEFER_OPEN);
    NetUtil.asyncCopy(istream, ostream, function(result) {
      callback && callback(file, result);
    });
  });
}

var file = Services.dirsvc.get("TmpD", Ci.nsIFile);
file.append("searchEngines.sqlite");
copyDataURLToFile(data.url("searchEngine.sqlite"), file, function(file, result) {
  console.log(result);
  console.log(file.exists());
  console.log(file.fileSize);
});

Solution 2:

Try using OS.File it's much more straight forward.

Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm")
var fromPath = FileUtils.getFile("ProfD", ["searchEngines.sqlite"]).path;
var toPath = FileUtils.getFile("TmpD", ["searchEngines.sqlite"]).path;;
var promise = OS.File.copy(fromPath, toPath);
var dbConn;
promise.then(
    function(aStat) {
        alert('success will now open connection');
        dbConn = Services.storage.openDatabase(toPath);
    },
    function(aReason) {
        console.log('promise rejected', aReason);
        alert('copy failed, see console for details');
    }
);

Post a Comment for "Copy File From Addon To Profile Folder"