我正在尝试将一个 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
打开 channel ),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
而不是 TmpD
中的 searchEngines.sqlite
,但是如果您更正了前面的陈述会适用)。
您只能在回调 .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
channel ,然后使用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);
});
关于javascript - 将文件从插件复制到配置文件文件夹,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24850460/