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

Copy file from addon to profile folder

本文关键字:配置文件 文件夹 复制 插件 文件      更新时间:2023-09-26

我正试图从我的扩展目录中的数据文件夹复制一个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)。

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

除了使用同步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()很可能为真,因为您已经打开了文件进行写入。只是这个文件仍然是空白的,因为数据拷贝还没有完成(甚至还没有开始)。(实际上,这是真的,因为你在ProfD中检查searchEngines.sqlite,而不是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);
});

尝试使用OS。文件更直接。

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