我有两种流程。一个人应该写一个文件,其他人应该阅读它,如果它被改变了。
如果他们必须重新加载文件,我找到fs.watch
来通知阅读流程。
要编写文件,我可以使用fs.writeFile
。
但我不确定,如果这是原子替代品。如果文件很大,watch
会多次触发吗?
将此作为原子操作的正确方法是什么?
仅供参考:在目标系统上运行Linux。
答案 0 :(得分:1)
经过一些测试后我得到了这个结果:
在写入大文件时, fs.watch
会多次触发change
事件。问题是,您无法看到写入操作已完成的最后一个问题。
解决方案是:将临时文件写在同一目录中,而不是使用link
和unlink
将旧文件替换为新文件。
在代码中它看起来像这样:
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
的文件并且只读,如果不同的话。