文章出處

自動保存的基本思路

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


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()