2013-11-22 43 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和只读,如果它不同。