zoukankan      html  css  js  c++  java
  • 软件项目技术点(21)——自动保存和恢复

    AxeSlide软件项目梳理   canvas绘图系列知识点整理

    自动保存的基本思路

    1)软件每次打开都会创建一个保存画布元素信息的文件,文件名是在打开软件时生成的唯一字符串。可同时打开多个窗口,所以保存文件路径下work/context文件夹里可能会有多个文件。

    2)每隔2分钟就更新一次context.json文件

    3)软件窗口正常关闭时将该窗口对应的context.json文件自动删除,如果仅打开了这一个窗口,将work下其他资源文件(插入的图片等)也删除掉。

         软件窗口如果是非正常关闭(电脑断电,电脑死机,软件崩溃等),context.json文件和work下的资源文件都不会被删除

    4)当软件再次被打开时,如果无其他窗口打开并且work/context目录下面有context.json文件存在,这时候软件会提醒有文件需要恢复保存。

    保存context.json文件

    针对过程2)每间隔2分钟context.json文件被保存一次,借助游戏主循环《软件项目技术点(1)——游戏主循环机制》,我们在循环主函数run()里添加如下代码,判断是否需要进行一次保存。

    1 //自动保存context
    2 if (!that.isGoto && editor.canvas.extendIntervalId < 0) {
    3     var autoSaveSetting = index.autoSaveContext;
    4     if (that.commonElements.count() >= 1 && curTime - autoSaveSetting.lastSaveTime > 60 * 1000 * <number>autoSaveSetting.saveTime) {
    5         autoSaveSetting.saveContext();
    6     }
    7 }

    如何将画布对象信息写入一个.json文件?

    我们先给大家认识一下我们代码里利用到的这三个fs函数

    (1)打开文件 

    fs.open(filename, flags, [mode], callback);
     1 // fs.open(filename, flags, [mode], callback);
     2 
     3 /**
     4  * filename, 必选参数,文件名
     5  * flags, 操作标识,如"r",读方式打开,'r' 写方式打开
     6  * [mode],权限,如777,表示任何用户读写可执行
     7  * callback 打开文件后回调函数,参数默认第一个err,
     8     第二个fd为一个整数,表示打开文件返回的文件描述符,window中又称文件句柄
     9  */
    10 
    11 fs.open(__dirname + '/test.txt', 'r', '0666', function (err, fd) {
    12   console.log(fd);
    13 });

    (2)写文件,将缓冲区内数据写入使用fs.open打开的文件

    fs.write(fd, buffer, offset, length, position, callback);
     1 //fs.write(fd, buffer, offset, length, position, callback);
     2 
     3 /**
     4  * fd, 使用fs.open打开成功后返回的文件描述符
     5  * buffer, 一个Buffer对象,v8引擎分配的一段内存
     6  * offset, 整数,从缓存区中读取时的初始位置,以字节为单位
     7  * length, 整数,从缓存区中读取数据的字节数
     8  * position, 整数,写入文件初始位置;
     9  * callback(err, written, buffer), 写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象
    10  */
    11 
    12 fs.open(__dirname + '/test.txt', 'a', function (err, fd) {
    13   if(err) {
    14     console.error(err);
    15     return;
    16   } else {
    17     var buffer = new Buffer('写入文件数据内容');
    18     //写入'入文件'三个字
    19     fs.write(fd, buffer, 3, 9, 12, function (err, written, buffer) {
    20       if(err) {
    21         console.log('写入文件失败');
    22         console.error(err);
    23         return;
    24       } else {
    25         console.log(buffer.toString());
    26         //写入'数据内'三个字
    27         fs.write(fd, buffer, 12, 9, null, function (err, written, buffer) {
    28           console.log(buffer.toString());
    29         })
    30       }
    31     });
    32   }
    33 });

    (3)刷新缓存区;

    fs.fsync(fd, [callback])
     1 // 使用fs.write写入文件时,操作系统是将数据读到内存,再把数据写入到文件中,当数据读完时并不代表数据已经写完,因为有一部分还可能在内在缓冲区内。
     2 // 因此可以使用fs.fsync方法将内存中数据写入文件;--刷新内存缓冲区;
     3 
     4 //fs.fsync(fd, [callback])
     5 /**
     6  * fd, 使用fs.open打开成功后返回的文件描述符
     7  * [callback(err, written, buffer)], 写入操作执行完成后回调函数,written实际写入字节数,buffer被读取的缓存区对象
     8  */
     9 
    10 fs.open(__dirname + '/test.txt', 'a', function (err, fd) {
    11   if(err)
    12     throw err;
    13   var buffer = new Buffer('我爱nodejs编程');
    14   fs.write(fd, buffer, 0, 9, 0, function (err, written, buffer) {
    15     console.log(written.toString());
    16     fs.write(fd, buffer, 9, buffer.length - 9, null, function (err, written) {
    17       console.log(written.toString());
    18       fs.fsync(fd);
    19       fs.close(fd);
    20     })
    21   });
    22 });

    注意:每个fd都要调用fs.close(fd)关闭流对象,否则会出错。

    我们使用上面介绍的三个fs的api函数完成将画布对象信息写入context.json文件的代码如下:

     1 //保存context文件
     2  saveContext() {
     3      var that = this;
     4      try {
     5          var dtoCore = editor.getDtoCore(true, false);
     6          var dtoCoreObj = JSON.decycle(dtoCore, true);
     7          var context = JSON.stringify(dtoCoreObj);
     8          Common.FileSytem.fsExt.open(Common.FileSytem.contextDir + this.saveContextPath + ".tmp", "w", function (err, fd) {
     9              if (err) {
    10                  Common.Logger.setErrLog(Common.LogCode.saveContext, "文件:AutoSaveContext,saveContext方法出错:" + err.message);
    11                  Common.FileSytem.fsExt.closeSync(fd);
    12              } else {
    13                  Common.FileSytem.fsExt.write(fd, context, function (err) {
    14                      if (err) {
    15                          Common.Logger.setErrLog(Common.LogCode.saveContext, "文件:AutoSaveContext,saveContext方法出错:" + err.message);
    16                          Common.FileSytem.fsExt.closeSync(fd);
    17                      } else {
    18                          Common.FileSytem.fsExt.fsync(fd, function (err) {
    19                              if (err) {
    20                                  Common.Logger.setErrLog(Common.LogCode.saveContext, "文件:AutoSaveContext,saveContext方法出错:" + err.message);
    21                                  Common.FileSytem.fsExt.closeSync(fd);
    22                              } else {
    23                                  Common.FileSytem.fsExt.closeSync(fd);
    24                                  Common.FileSytem.fsExt.rename(Common.FileSytem.contextDir + that.saveContextPath + ".tmp", Common.FileSytem.contextDir + that.saveContextPath, function (err) {
    25                                      if (err) {
    26                                          Common.Logger.setErrLog(Common.LogCode.saveContext, "文件:AutoSaveContext,saveContext方法出错:" + err.message);
    27                                      }
    28                                  });
    29                              }
    30                          })
    31                      }
    32                  })
    33              }
    34          });
    35      } catch (err) {
    36          Common.Logger.setErrLog(Common.LogCode.saveContext, "文件:AutoSaveContext,saveContext方法出错:" + err.message);
    37      }
    38 
    39      this.lastSaveTime = Date.now();//执行本次保存的具体时间点
    40  }

    注意:跟保存作品一样,为避免一个已存在context文件再次保存时失败将已存在的正确文件覆盖掉,我们新建文件context.json.tmp,文件写入成功后再重命名为context.json文件。

    检查是否有需要修复文件

    在关闭软件窗口时需要判断是否有需要修复文件,以此得出是否要删除资源

    在软件打开时也需要判断是否有需要修复文件,以此控制是否需要弹出恢复文件窗口

     1 //检查是否有需要修复的文件
     2 isNeedToRestore(callback: Function = null) {
     3     var that = this;
     4     var fileList = Common.FileSytem.readDirSync(Common.FileSytem.contextDir);//如果context文件夹下没有文件时,说明没有需要修复的文件再进行清除
     5     fileList.forEach(function (name, i) {
     6         if (name.indexOf(".tmp") == -1) {//临时文件.tmp不包含在内
     7             that.needRestoreNames.push(name);
     8         }
     9     })
    10     if (that.needRestoreNames.length >= 1) {
    11         var allWindows = chrome.app.window.getAll();//获取打开软件窗口的个数
    12         if (that.needRestoreNames.length >= 1 && allWindows.length == 1) {//如果context.json有多个,且只打开一个软件窗口情况
    13             return true;
    14         } else {
    15             return false;
    16         }
    17 
    18     } else {
    19         return false;
    20     }
    21 }

    恢复文件

    跟保存文件的过程是一样的《软件项目技术点(19)——文件的保存和打开(解压缩)

    fs用法参考资料:

    http://www.jianshu.com/p/5683c8a93511

  • 相关阅读:
    Django集成Markdown编辑器【附源码】
    Django+JWT实现Token认证
    Docker环境的持续部署优化实践
    2018-行远自迩,登高自卑
    SVN Hooks的介绍及使用
    Django开发密码管理表实例【附源码】
    Django+Echarts画图实例
    Django使用Signals监测model字段变化发送通知
    运维效率之数据迁移自动化
    Python之路(第三十四篇) 网络编程:验证客户端合法性
  • 原文地址:https://www.cnblogs.com/fangsmile/p/6283560.html
Copyright © 2011-2022 走看看