我想在我的cordova应用程序中添加一些简单的日志记录功能。
所以我添加了文件插件,实现了一个超级简单的日志方法并进行了测试。
我的配置:
$ cordova --version
3.5.0-0.2.7
$ cordova plugins
org.apache.cordova.file 1.3.0 "File"
测试设备是华为u8850,运行Android 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
有两个问题:
我认为问题的原因是文件方法的异步性质。但这只是猜测。
问题是:
答案 0 :(得分:1)
可能你在之前的写作完成之前尝试写,并解雇了onwriteend
事件。
正如我在第一个问题的回答中所述,实现caching
功能是个好主意。
因此,您的所有日志都将存储在临时cache
中。每次向此cache
添加内容时,您都会检查它的大小,一旦达到您定义的限制,请调用logDumping
方法,该方法将是实际的write
日志文件。
当您调用dump
方法时,您可以将日志内容传递给编写者并清空缓存,这样您就可以在其中存储新内容,并且它不会与已经记录重叠内容。
我要做的是:
cache
日志cache
是否达到了尺寸限制cache
的内容传递给tmp_var
并清除cache
tmp_var
写入logfile onwriteend
>如果成功清除tmp_var
,如果出现错误,您可以将tmp_var
写回实际的cache
(因此不会丢失任何数据),并尝试编写{{1}的内容再次登录你的日志文件。答案 1 :(得分:1)
#include "stdio.h"
void appendLine(char* path_to_file, char* line) {
FILE* fp = fopen(path_to_file, "a");
if (fp) {
fprintf(fp, "%s\n", line);
fclose(fp);
}
}
int main(){
appendLine("logfile.txt", "One Line");
appendLine("logfile.txt", "Another Line");
return 0;
}
这是用一种叫做“C”的古老语言写成的。
只需4行代码:
可以使用以下命令编译:
gcc -Wall addline.c -o addline
并且这样开始:
./addline
输出将是这样的:
One Line
Another Line
不幸的是,在使用phonegap / cordova编写基于JS的应用程序时无法做到这一点。
由于未知原因,基本文件操作的简单同步接口不是phonegaps核心实现的一部分,另外不包含在'file'插件中。
所以我花了一些时间来实现一个简单的TextFile包装器来完成脏工作,所以客户端应用程序可以使用这样的简单命令:
// 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});
}
}
};
})();
也许这对其他人有用,在同样的问题上挣扎......