File 使用phonegap/cordova文件插件的问题第2部分-同步性

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应用程序中添加一些简单的日志功能

所以我添加了文件插件,实现了一个超级简单的日志方法并进行了测试

我的配置:

    $ 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});
                }
            }
        };
    })();