目录上的NodeJS fs.watch仅在编辑器更改时触发,而不是shell或fs模块

Bij*_*lle 8 macos fs node.js

当运行下面的代码时,只有在我使用ide,TextEditor.app或vim手动编辑和保存tmp.txt时才会触发监视.

它不是通过写入流或手动shell输出重定向的方法(键入echo"test"> /path/to/tmp.txt").

虽然如果我看文件本身,而不是它的名字,那么它是有效的.

var fs, Path, file, watchPath, w;

fs = require('fs' );
Path = require('path');
file = __dirname + '/tmp.txt';
watchPath = Path.dirname(file); // changing this to just file makes it trigger

w = fs.watch ( watchPath, function (e,f) {
    console.log("will not get here by itself");
    w.close();
});
fs.writeFileSync(file,"test","utf-8");

fs.createWriteStream(file, {
    flags:'w',
    mode: 0777
} )
.end('the_date="'+new Date+'";' ); // another method fails as well

setTimeout (function () {
    fs.writeFileSync(file,"test","utf-8");
},500); // as does this one
// child_process exec and spawn fail the same way with or without timeout
Run Code Online (Sandbox Code Playgroud)

所以问题是:为什么?以及如何从节点脚本以编程方式触发此事件?

谢谢!

sar*_*old 11

问题是,你已经要求观看目录而不是文件.

修改文件时不更新目录,例如通过shell重定向; 在这种情况下,文件被打开,修改和关闭.目录不会更改 - 只有文件是.

当您使用文本编辑器修改文件时,幕后的常用系统调用看起来像这样:

fd = open("foo.new")
write(fd, new foo contents)
unlink("foo")
rename("foo.new", "foo")
Run Code Online (Sandbox Code Playgroud)

这样,foo文件完全是旧文件或完全是新文件,并且没有办法使用新内容的"部分文件".重命名操作修改目录,从而触发目录监视.


aba*_*ert 11

它不会触发,因为对文件内容的更改不是对目录的更改.

在封面上,至少从0.6开始,fs.watch在Mac上使用kqueue,它是围绕kqueue文件系统通知的一个非常薄的包装器.所以,如果你真的想了解细节,你必须了解kqueue,inode和类似的东西.

但是如果你想要一个简短的"撒谎到孩子"的解释:用户认为什么是"文件"实际上是两个独立的东西 - 实际文件,以及指向实际文件的目录条目.这使您可以使用硬链接以及即使在删除它们之后仍然可以读取和写入的文件,等等.

通常,当您写入现有文件时,这不会对目录条目进行任何更改,因此观看该目录的任何人都不会看到任何更改.这就是echo> tmp.txt不会触发你的原因.

但是,如果您,例如,编写一个新的临时文件,然后将其移动到旧文件上,那确实会更改目录条目(使其成为指向新文件而不是旧文件的指针),因此您将收到通知.这就是TextEditor.app确实触发你的原因.