2013-11-22 86 views
1

我有兩種進程。一個人應該寫一個文件,其他人應該讀它,如果它被改變。nodejs:原子文件替換操作,一次只觸發一次觀察者

我發現fs.watch得到通知閱讀過程,如果他們必須重新加載文件。

要寫入文件,我可以使用fs.writeFile

但我不確定,如果這是原子替換。如果文件很大,將會觸發watch幾次?

什麼是正確的方法,將其作爲原子操作?

僅供參考:在目標系統上運行Linux。而大型文件被寫入

fs.watchchange事件多次觸發:

回答

1

一些測試後,我得到了這個結果。問題是,你無法看到,最後一個發現,寫入操作已經完成。

解決方案是:在同一目錄中寫一個臨時文件,比使用linkunlink用新的替換舊文件。

在代碼中它可能看起來像這樣:

var fs = require("fs"); 
var path = require("path"); 
var consts = require('constants'); 

/** 
* write given date in temp file and replace the dstpath with that. 
* 
* @author Tobias Lindig 
* 
* @param {string} dstpath destination path 
* @param {string} data [description] 
* 
* @throws {Error} If fs operations failed. 
*/ 
function atomicWrite(dstpath, data) { 
    // build a unique temp path 
    var dir = path.dirname(dstpath); 
    var tempName = [ 
     'temp', 
     process.pid, 
     (Math.random() * 0x1000000000).toString(36), 
     new Date().getTime() 
    ].join('-'); 
    var tempPath = path.join(dir, tempName); 

    var tempOptions = { 
     encoding: 'utf8', 
     mode: 420, // aka 0644 in Octal 
     flags: consts.O_CREAT | consts.O_TRUNC | consts.O_RDWR | consts.O_EXCL 
    }; 

    //local function to remove temp file 
    var fn_removeTempFileSync = function() { 
     try { 
      fs.unlinkSync(tempPath); 
     } catch (ex) { 
      // ignore fail, may be file was not created. 
     } 
    }; 

    try { 
     fs.writeFileSync(tempPath, data, tempOptions); 

     // remove possible old version of file 
     // because fs.link can not overwrite existing dstpath. 
     if (fs.existsSync(dstpath)) { 
      fs.unlinkSync(dstpath); 
     } 

     //copy temp file to destination path 
     fs.linkSync(tempPath, dstpath); 

     fn_removeTempFileSync(); 
    } catch (ex) { 
     fn_removeTempFileSync(); 
     throw ex; 
    } 
} 

現在fs.watch火災的文件( 「dstpath」)的事件change一次。

那理論。

但在現實世界中,不幸的是,change事件並未在任何情況下觸發,有的時候它錯過了。所以我也看過rename事件。

的事件會在這個順序:

rename //不斷,如果文件被刪除 rename //不斷,文件被創建 change //一些時間,文件被創建

閱讀該文件只有一次,我會員文件的mtime和只讀,如果它不同。