File 使用phonegap/cordova文件插件的问题第2部分-同步性
我想在我的cordova应用程序中添加一些简单的日志功能 所以我添加了文件插件,实现了一个超级简单的日志方法并进行了测试 我的配置:File 使用phonegap/cordova文件插件的问题第2部分-同步性,file,cordova,phonegap-plugins,cordova-3,File,Cordova,Phonegap Plugins,Cordova 3,我想在我的cordova应用程序中添加一些简单的日志功能 所以我添加了文件插件,实现了一个超级简单的日志方法并进行了测试 我的配置: $ cordova --version 3.5.0-0.2.7 $ cordova plugins org.apache.cordova.file 1.3.0 "File" 测试设备为华为u8850,运行安卓2.3.5 记录器: window.MyLog = { log: function(line){
$ cordova --version
3.5.0-0.2.7
$ cordova plugins
org.apache.cordova.file 1.3.0 "File"
测试设备为华为u8850,运行安卓2.3.5
记录器:
window.MyLog = {
log: function(line){
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(FS) {
FS.root.getFile('the_log3.txt', {"create":true, "exclusive":false},
function(fileEntry) {
fileEntry.createWriter(
function(writer) {
console.log(line);
writer.seek(writer.length); // append to eof
writer.write(line + '\n'); // write the line
}, fail);
}, fail);
}, fail);
}
};
测试:
MyLog.log('A ' + new Date().toLocaleTimeString());
MyLog.log('B ' + new Date().toLocaleTimeString());
MyLog.log('C ' + new Date().toLocaleTimeString());
我启动了3次应用程序,期望像这样
A 16:03:47
B 16:03:47
C 16:03:47
A 16:04:34
B 16:04:34
C 16:04:34
A 16:04:41
B 16:04:41
C 16:04:41
但我明白了
C 16:03:47
C 16:04:34
A 16:04:41
有两个问题:
可能是您试图在以前的写入完成之前进行写入,并触发了
onwriteend
事件
正如我在回答第一个问题时所说,实现缓存
功能是个好主意
因此,所有日志都将存储在临时缓存中。每次向该缓存添加内容时
都会检查其大小,一旦达到您定义的限制,请调用logDumping
方法,该方法将实际写入日志文件
调用dump
方法时,您可以将日志内容传递给编写器,并清空缓存,以便在其中存储新内容,而不会与已记录的内容重叠
我要做的是:
缓存日志
检查缓存是否达到大小限制
将cache
的内容传递给tmp\u var
并清除cache
将tmp\u var
写入日志文件
检查onwriteend
>如果成功清除tmp\u var
,如果出现错误,您可以将tmp\u var
写回实际的缓存(因此不会丢失任何数据),然后再次尝试将缓存的内容写入日志文件
这是用一种叫做“C”的古代语言写的
只有4行代码:
fopen:打开现有文件或创建新文件,文件位置在末尾(“a”表示追加)
if(fp):检查是否创建了文件对象
做吧李>
fclose:关闭它(并刷新内容)
可以使用以下命令对其进行编译:
gcc -Wall addline.c -o addline
开始是这样的:
./addline
输出如下所示:
One Line
Another Line
不幸的是,在使用phonegap/cordova编写基于JS的应用程序时,这是无法做到的
由于未知原因,phonegaps核心实现中不包含用于基本文件操作的简单同步接口,此外,“文件”插件中也不包含该接口
因此,我花了一些时间实现了一个简单的文本文件包装器来完成这些脏活,因此客户端应用程序可以使用以下简单命令:
// a single object is the wrapper:
var textFile;
function init() {
// ...
// initialize the (log) file
// the file will be created if doesn't exists
// when sth. goes wrong, the callback has an error message
textFile = new TextFile('logfile.txt', function(ok, msg){
if (!ok) {
alert('logging not available' + (msg ? '\nError: ' + msg : ''));
textFile = null;
} else {
textFile.writeLine('start logging ...');
start();
}
},
{
// optional options, currently just one property 'clear' is supported
// if set to true, the file will be emptied at start
clear: true
}
);
// later, use methods
// append some lines
textFile.writeLine('a line');
textFile.writeLine('another line');
// get content, callback needed since it is not synchronous
textFile.getContent(function(text){
// show text
});
// empty file
textFile.clear();
// remove file
textFile.remove();
我使用jquery合并选项-如果jquery不合适,只需替换$.extend方法即可
代码如下:
/**
* Created by martin on 9/3/14.
*
* requires the file plugin:
*
* cordova plugin add org.apache.cordova.file
*
* implemented and tested with
* cordova-3.5.0-0.2.7
* on
* Android 2.3.5
*/
(function(){
'use strict';
// these values are NOT part of FileWriter, so we had to define them:
const INIT = 0;
const WRITING = 1;
const DONE = 2;
function errMessage(code){
var msg = '';
switch (code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
return msg;
}
/**
*
* @param fileName : the name of the file for which the TextFile is created
* @param cb : function, is called when
* - TextFile is created, parameter: boolean true
* - TextFile is not created, parameters: boolean false, string error_message
* @param options : object with single property
* - boolean clear - truncates the file, defaults to false
* @constructor
*/
window.TextFile = function(fileName, cb, options){
this.writer = null;
this.queue = [];
this.fileEntry = null;
this._initialize(fileName, cb, options);
}
var files = {};
TextFile.prototype = {
// pseudo private method, called form constructor
_initialize: function(fileName, cb, options){
this.options = $.extend({startMsg: null, clear: false}, options)
if (files.fileName) {
cb(false, 'TextFile[' + fileName + '] already in use');
}
files.fileName = true;
var that = this;
window.requestFileSystem(
LocalFileSystem.PERSISTENT,
0,
function(FS) {
FS.root.getFile(
fileName,
{
'create': true,
'exclusive': false
},
function(fileEntry) {
that.fileEntry = fileEntry;
fileEntry.createWriter(
function(writer) {
that.writer = writer;
writer.seek(writer.length);
writer.onwriteend = function(){
if (that.queue.length > 0){
// sth in the queue
var item = that.queue[0];
switch (item.type) {
case 'w':
writer.write(item.line + '\n');
break;
case 't':
writer.truncate(0);
break;
case 'g':
that._readContent(item.cb);
break;
default:
throw 'unknown type ' + item.type;
}
// get rid of processed item
that.queue.splice(0, 1);
}
}
if (that.options.clear) {
that.clear();
}
cb(true);
}
);
},
function(err){
cb(false, errMessage(err.code))
}
);
},
function(){
cb(false, errMessage(err.code));
}
);
},
// internal use
_readContent: function(cb){
this.fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var res = this.result;
cb(res);
};
reader.readAsText(file);
},
function(err) {
cb('got an error: ' + errMessage(err.code));
}
);
},
// reads whole file, content is sent to client with callback
getContent: function(cb){
if (this.writer.readyState !== WRITING) {
this._readContent(cb);
} else {
this.queue.push({type: 'g', cb:cb});
}
},
// set file size to zero
clear: function() {
if (this.writer.readyState !== WRITING) {
this.writer.truncate(0);
} else {
this.queue.push({type: 't'});
}
},
// removes file
remove: function(cb){
this.fileEntry.remove(
function(){
if (cb) {
cb(true);
}
},
function(err){
if (cb) {
cb(false,errMessage(err.code));
}
}
);
},
// append single line to file
writeLine: function(line){
if (this.writer.readyState !== WRITING) {
this.writer.write(line + '\n');
} else {
this.queue.push({type: 'w', line: line});
}
}
};
})();
也许这对其他人来说是有用的,他们正在为同样的问题挣扎
/**
* Created by martin on 9/3/14.
*
* requires the file plugin:
*
* cordova plugin add org.apache.cordova.file
*
* implemented and tested with
* cordova-3.5.0-0.2.7
* on
* Android 2.3.5
*/
(function(){
'use strict';
// these values are NOT part of FileWriter, so we had to define them:
const INIT = 0;
const WRITING = 1;
const DONE = 2;
function errMessage(code){
var msg = '';
switch (code) {
case FileError.QUOTA_EXCEEDED_ERR:
msg = 'QUOTA_EXCEEDED_ERR';
break;
case FileError.NOT_FOUND_ERR:
msg = 'NOT_FOUND_ERR';
break;
case FileError.SECURITY_ERR:
msg = 'SECURITY_ERR';
break;
case FileError.INVALID_MODIFICATION_ERR:
msg = 'INVALID_MODIFICATION_ERR';
break;
case FileError.INVALID_STATE_ERR:
msg = 'INVALID_STATE_ERR';
break;
default:
msg = 'Unknown Error';
break;
};
return msg;
}
/**
*
* @param fileName : the name of the file for which the TextFile is created
* @param cb : function, is called when
* - TextFile is created, parameter: boolean true
* - TextFile is not created, parameters: boolean false, string error_message
* @param options : object with single property
* - boolean clear - truncates the file, defaults to false
* @constructor
*/
window.TextFile = function(fileName, cb, options){
this.writer = null;
this.queue = [];
this.fileEntry = null;
this._initialize(fileName, cb, options);
}
var files = {};
TextFile.prototype = {
// pseudo private method, called form constructor
_initialize: function(fileName, cb, options){
this.options = $.extend({startMsg: null, clear: false}, options)
if (files.fileName) {
cb(false, 'TextFile[' + fileName + '] already in use');
}
files.fileName = true;
var that = this;
window.requestFileSystem(
LocalFileSystem.PERSISTENT,
0,
function(FS) {
FS.root.getFile(
fileName,
{
'create': true,
'exclusive': false
},
function(fileEntry) {
that.fileEntry = fileEntry;
fileEntry.createWriter(
function(writer) {
that.writer = writer;
writer.seek(writer.length);
writer.onwriteend = function(){
if (that.queue.length > 0){
// sth in the queue
var item = that.queue[0];
switch (item.type) {
case 'w':
writer.write(item.line + '\n');
break;
case 't':
writer.truncate(0);
break;
case 'g':
that._readContent(item.cb);
break;
default:
throw 'unknown type ' + item.type;
}
// get rid of processed item
that.queue.splice(0, 1);
}
}
if (that.options.clear) {
that.clear();
}
cb(true);
}
);
},
function(err){
cb(false, errMessage(err.code))
}
);
},
function(){
cb(false, errMessage(err.code));
}
);
},
// internal use
_readContent: function(cb){
this.fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var res = this.result;
cb(res);
};
reader.readAsText(file);
},
function(err) {
cb('got an error: ' + errMessage(err.code));
}
);
},
// reads whole file, content is sent to client with callback
getContent: function(cb){
if (this.writer.readyState !== WRITING) {
this._readContent(cb);
} else {
this.queue.push({type: 'g', cb:cb});
}
},
// set file size to zero
clear: function() {
if (this.writer.readyState !== WRITING) {
this.writer.truncate(0);
} else {
this.queue.push({type: 't'});
}
},
// removes file
remove: function(cb){
this.fileEntry.remove(
function(){
if (cb) {
cb(true);
}
},
function(err){
if (cb) {
cb(false,errMessage(err.code));
}
}
);
},
// append single line to file
writeLine: function(line){
if (this.writer.readyState !== WRITING) {
this.writer.write(line + '\n');
} else {
this.queue.push({type: 'w', line: line});
}
}
};
})();