将文件从插件复制到配置文件文件夹

时间:2014-07-20 12:23:39

标签: javascript firefox firefox-addon firefox-addon-sdk

我试图将sqlite数据库从我的扩展目录中的数据文件夹复制到配置文件文件夹,以便使用它。

所以现在,我正在尝试:

const {Cc, Ci, Cu} = require("chrome");
const {NetUtils} = Cu.import("resource://gre/modules/NetUtil.jsm");
const data = require('sdk/self').data;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/FileUtils.jsm");

var file = Cc["@mozilla.org/file/directory_service;1"].
       getService(Ci.nsIProperties).
       get("TmpD", Ci.nsIFile);
file.append("searchEngines.sqlite");
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);

// Then, we need an output stream to our output file.
var ostream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
ostream.init(file, -1, -1, 0);

// Finally, we need an input stream to take data from.
var iStreamData = NetUtil.ioService.newChannel(data.url("searchEngines.sqlite"), null, null).open();
let istream = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
istream.setData(iStreamData, iStreamData.length);

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

console.log(FileUtils.getFile("ProfD", ["searchEngines.sqlite"]).exists()); // return false

let dbConn = Services.storage.openDatabase(file);

该文件似乎存在,因为console.log(file.exists())返回FALSE并且未填充(console.log(aResult)返回0)。

我的错误在哪里,有没有更好的方法呢?

2 个答案:

答案 0 :(得分:3)

除了它使用同步I / O(用.open而不是.asyncOpen打开频道),NetUtil.asyncCopy操作仍然是异步的,这意味着代码

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

console.log(FileUtils.getFile("ProfD", ["searchEngines.sqlite"]).exists()); // return false

let dbConn = Services.storage.openDatabase(file);

将尝试打开文件之前副本可能完成! 但是,file.exists()可能是正确的,因为您已经打开了要写入的文件。只是文件仍然是空白的,因为数据拷贝还没有完成(甚至还没有开始)。 (实际上,确实如此,因为您正在searchEngines.sqlite而不是ProfD中检查TmpD,但如果您更正了以前的陈述将会适用的话。)

您只能在回复.asyncCopy后/之后使用该文件,例如

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

PS:您可能希望.asyncOpen该频道,然后使用NetUtil.asyncFetch并将生成的流传递给.asyncCopy,以便对于小文件真正异步,因为这会将内容缓存到内存中第一

对于大型文件,您可以创建NetUtil.asyncFetch实施的变体,将.outputStream端直接提供给NetUtils.asyncCopy。这有点复杂,所以我不会详细地写这篇文章,直到有人对此真正感兴趣并提出相应的问题。

编辑,以下是我编写的方式:

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

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

function copyDataURLToFile(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);
});

答案 1 :(得分:0)

尝试使用OS.File它更直接。

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');
    }
);