当我更改监视文件时,fs.watch会两次触发

时间:2012-10-19 16:56:09

标签: node.js windows-8 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');
   });
 });

输出:

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

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

13 个答案:

答案 0 :(得分:39)

fs.watch api:

  1. unstable
  2. 关于重复通知,
  3. known "behaviour"。具体来说,windows case是Windows设计的结果,其中单个文件修改可以是多次调用windows API

答案 1 :(得分:16)

我通过以下方式考虑到这一点:

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
    }
}

答案 2 :(得分:13)

我建议使用chokidarhttps://github.com/paulmillr/chokidar),这比fs.watch要好得多:

  

评论其README.md:

Node.js fs.watch

  • 不报告OS X上的文件名。
  • 在OS X上使用Sublime等编辑器时,根本不报告事件。
  • 经常报告两次事件。
  • 将大部分更改发布为rename
  • a lot of other issues
  • 不提供递归查看文件树的简便方法。

Node.js fs.watchFile

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

答案 3 :(得分:9)

如果您需要查看文件以进行更改,那么您可以查看我的小型图书馆on-file-change。它检查已触发的change事件之间的文件sha1哈希值。

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

  

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

Source

答案 4 :(得分:1)

首先是更改,第二个是重命名

我们可以从侦听器功能

中发挥作用
function(event, filename) {

}

侦听器回调获取两个参数(event,filename)。 event是'rename'或'change',filename是触发事件的文件的名称。

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

当一个源文件被重命名为targetfile时,它会将三个事件称为事实

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

请注意,如果你想抓住所有这三个evnet,请观看源文件的目录

答案 5 :(得分:1)

我是第一次处理这个问题,所以到目前为止所有答案都可能比我的解决方案更好,但是没有一个是100%适合我的情况所以我想出了一些略有不同的东西 - 我使用XOR操作来翻转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;
}

我不想使用与时间相关的功能(如jwymanm的回答),因为我正在观看的文件可能会非常频繁地获得合法更新。而且我不想使用像Erik P建议的观看文件列表,因为我只看一个文件。 JanŚwięcki的解决方案似乎有点矫枉过正,因为我正在低功耗环境中处理极短且简单的文件。最后,Bernado的回答让我有些紧张 - 如果它在我完成第一次处理之前到达它只会忽略第二次更新,我无法处理那种不确定性。如果有人发现自己处于这种非常具体的情况,那么我使用的方法可能有一些优点吗?如果有任何重大错误,请让我知道/编辑这个答案,但到目前为止似乎运作良好?

注意:显然,此强烈假设您每次实际更改都会获得2个事件。显然,我仔细测试了这个假设,并了解了它的局限性。到目前为止,我已经确认:

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

我可以想到不同行为的完美原因,但我们不需要知道为什么正在发生的事情来计划它 - 我只想强调你要检查在你自己的环境和你自己的用例(duh)的背景下自己,而不是相信互联网上一个自认为白痴的人。话虽这么说,采取预防措施,到目前为止我并没有任何奇怪。

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

答案 6 :(得分:1)

我的自定义解决方案

我个人喜欢使用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); }; 来阻止在检查某些内容时运行代码块,因此,这是我的方法:

{{1}}

您可以随意使用此示例来简化代码。 NOT 可能比使用其他人的模块更好,但效果非常好!

答案 7 :(得分:0)

我有时会看到Watch事件的多次注册,导致Watch事件多次触发。 我通过保留一个观察文件列表来解决它,并避免在文件已经在列表中时注册事件:

 var watchfiles = {};

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

...

答案 8 :(得分:0)

相似/同样的问题。当它们被添加到目录中时,我需要对图像做一些事情。以下是我处理双击的方法:

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;
});

它将忽略第二次触发,直到完成与新文件有关的操作。

答案 9 :(得分:0)

像其他人一样,答案说......这有很多麻烦,但我可以这样处理:

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
        }
    }
});

希望我可以帮助你...

答案 10 :(得分:0)

最简单的解决方案:

spotlightLondon

答案 11 :(得分:0)

我正在使用puppeteer下载文件,一旦保存了文件,我将自动发送电子邮件。由于上述问题,我注意到我正在发送2封电子邮件。我通过使用process.exit()停止应用程序并使用pm2自动启动来解决了。在代码中使用标志并不能挽救我。

如果将来有人遇到此问题,则也可以使用此解决方案。退出程序并使用监视工具自动重新启动。

答案 12 :(得分:0)

这是我的简单解决方案。每次都运行良好。

// Update obj as file updates
obj = JSON.parse(fs.readFileSync('./file.json', 'utf-8'));
fs.watch('./file.json', () => {
  const data = JSON.parse(fs.readFileSync('./file.json', 'utf-8') || '{}');
  if(Object.entries(data).length > 0) { // This checks fs.watch() isn't false-firing
    obj = data;
    console.log('File actually changed: ', obj)
  }
});