我试图将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)。
我的错误在哪里,有没有更好的方法呢?
答案 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');
}
);