当我改变观看的文件时,fs.watch发射了两次

fs.watch( 'example.xml', function ( curr, prev ) { // on file change we can read the new xml fs.readFile( 'example.xml','utf8', function ( err, data ) { if ( err ) throw err; console.dir(data); console.log('Done'); }); }); 

OUTPUT:

  • 一些数据
  • 完成X 1
  • 一些数据
  • 完成X 2

这是我的用法错误还是..?

fs.watch api:

  1. 是不稳定的
  2. 已经知道“重复通知”的“行为” 。 具体来说, windows的情况是windowsdevise的结果,其中一个文件修改可以多次调用windows API

我通过以下做法来弥补这一点:

 var fsTimeout fs.watch('file.js', function(e) { if (!fsTimeout) { console.log('file.js %s event', e) fsTimeout = setTimeout(function() { fsTimeout=null }, 5000) // give 5 seconds for multiple events } } 

我build议与chokidarhttps://github.com/paulmillr/chokidar )比fs.watch好得多:

评论其README.md:

Node.js fs.watch

  • 不报告OS X上的文件名。
  • 在OS X上使用像Sublime这样的编辑器时根本不报告事件。
  • 经常报道事件两次。
  • 作为rename发出大部分更改。
  • 还有很多其他的问题
  • 不提供recursion监视文件树的简单方法。

Node.js fs.watchFile

  • 事件处理几乎一样糟糕。
  • 也不提供任何recursion观看。
  • 导致CPU利用率高。

如果你需要看你的文件的变化,那么你可以看看我的小图书馆的文件更改 。 它检查change事件之间的文件sha1哈希。

为什么我们有多个被触发的事件的解释:

您可能会注意到在某些情况下,单个创build事件会生成由组件处理的多个创build事件。 例如,如果使用FileSystemWatcher组件监视目录中新文件的创build,然后使用记事本testing它以创build文件,则即使只创build了一个文件,也可能会看到两个创build的事件。 这是因为记事本在写入过程中执行多个文件系统操作。 记事本批量写入磁盘,创build文件的内容,然后创build文件属性。 其他应用程序可能以相同的方式执行。 由于FileSystemWatcher监视操作系统活动,所以这些应用程序触发的所有事件都将被拾取。

资源

首先是变化,第二是重命名

我们可以从听众的function上有所作为

 function(event, filename) { } 

监听器callback获得两个参数(事件,文件名)。 事件是“重命名”或“更改”,文件名是触发事件的文件的名称。

 // rm sourcefile targetfile fs.watch( sourcefile_dir , function(event, targetfile)){ console.log( targetfile, 'is', event) } 

作为源文件被重命名为目标文件,它将作为事实调用三个事件

 null is rename // sourcefile not exist again targetfile is rename targetfile is change 

注意,如果你想捕获所有这三个evnet,请看sourcefile的目录

我是第一次处理这个问题,所以到目前为止所有的答案都可能比我的解决scheme好,但是没有一个是100%适合我的情况,所以我想出了一些稍微不同的东西 – 我使用异或操作来翻转0到1之间的整数,有效地跟踪和忽略文件上的每一秒事件:

 var targetFile = "./watchThis.txt"; var flippyBit = 0; fs.watch(targetFile, {persistent: true}, function(event, filename) { if (event == 'change'){ if (!flippyBit) { var data = fs.readFile(targetFile, "utf8", function(error, data) { gotUpdate(data); }) } else { console.log("Doing nothing thanks to flippybit."); } flipBit(); // call flipBit() function } }); // Whatever we want to do when we see a change function gotUpdate(data) { console.log("Got some fresh data:"); console.log(data); } // Toggling this gives us the "every second update" functionality function flipBit() { flippyBit = flippyBit ^ 1; } 

我不想使用时间相关的function(如jwymanm的答案),因为我正在观看的文件可能假设得到合法的更新非常频繁。 而且我不想使用像Erik Pbuild议的那样观看的文件列表,因为我只能看一个文件。 一月Święcki的解决scheme似乎是矫枉过正,因为我正在低功耗环境下工作的极短,简单的文件。 最后,伯纳多的回答让我有点紧张 – 如果在第一次处理完之前,它只会忽略第二次更新,我不能处理这种不确定性。 如果有人发现自己在这个特定的情况下,我用这个方法可能有一些好处吗? 如果有什么大问题,请让我知道/编辑这个答案,但到目前为止似乎运作良好?

注意:显然,这强烈假定每次实际更改都会得到2个事件。 我仔细地testing了这个假设,显然,并且学会了它的局限性。 到目前为止,我已经证实:

  • 在Atom编辑器中修改文件并保存触发器2更新
  • touch触发2更新
  • 通过> (覆盖文件内容)输出redirect触发2个更新
  • 通过追加>> 有时触发1更新! *

我可以为不同的行为考虑完美的理由,但是我们不需要知道为什么会发生一些事情,我只是想强调一下,你会想要在自己的环境和上下文中检查自己你自己的用例(杜),而不是相信在互联网上自认白痴。 这就是说,采取预防措施,到目前为止我还没有任何古怪的东西。

*完全披露,实际上我不知道为什么会发生这种情况,但是我们已经用watch()函数处理了不可预测的行为,所以有什么更多的不确定性呢? 对于在家里跟随的任何人,更快速地附加到文件似乎会导致它停止双重更新,但老实说,我真的不知道,我很满意这种解决scheme在实际情况下的行为被使用,这是一个单行文件,将被更新(内容replace),如最快的每秒两次。

我很多时候得到Watch事件的多重注册,导致Watch事件触发几次。 我通过保持观看文件的列表来解决这个问题,并且避免在文件allready在列表中的情况下注册事件:

  var watchfiles = {}; function initwatch(fn, callback) { if watchlist[fn] { watchlist[fn] = true; fs.watch(fn).on('change', callback); } } 

……

类似/相同的问题。 当他们被添加到目录时,我需要做一些与图像的东西。 以下是我如何处理双重射击:

 var fs = require('fs'); var working = false; fs.watch('directory', function (event, filename) { if (filename && event == 'change' && active == false) { active = true; //do stuff to the new file added active = false; }); 

它将忽略第二次射击,直到完成与新文件的关系。

像其他人的回答说…这有很多麻烦,但我可以用这种方式处理这个问题:

 var folder = "/folder/path/"; var active = true; // flag control fs.watch(folder, function (event, filename) { if(event === 'rename' && active) { //you can remove this "check" event active = false; // ... its just an example for (var i = 0; i < 100; i++) { console.log(i); } // ... other stuffs and delete the file if(!active){ try { fs.unlinkSync(folder + filename); } catch(err) { console.log(err); } active = true } } }); 

希望我能帮你…

最简单的解决scheme

 const watch = (path, opt, fn) => { var lock = false fs.watch(path, opt, function () { if (!lock) { lock = true fn() setTimeout(() => lock = false, 1000) } }) } watch('/path', { interval: 500 }, function () { // ... }) 

我的定制解决scheme

我个人喜欢使用return来防止检查某些代码时运行,所以,这里是我的方法:

 var watching = false; fs.watch('./file.txt', () => { if(!watching) return; watching = true; // do something // the timeout is to prevent the script to run twice with short functions // the delay can be longer to disable the function for a set time setTimeout(() => { watching = false; }, 100); }; 

随意使用这个例子来简化你的代码。 它可能不会比使用其他模块更好,但它工作得很好!