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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当我更改监视文件时,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. unstable
  2. 有重复通知的known "behaviour"。具体来说,windows case是windows设计的结果,其中单个文件修改可以多次调用windows API
另一答案

像其他人一样,答案说......这有很多麻烦,但我可以用这种方式解决这个问题:

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

希望我可以帮助你......

另一答案

最简单的解决方案

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 () {
  // ...
})
另一答案

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

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
    }
}
另一答案

我建议使用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利用率。
另一答案

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

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

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

Source

另一答案

第一个是改变,第二个是重命名

我们可以从监听器功能中有所作为

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,请观看sourcefile的目录

另一答案

我是第一次处理这个问题,所以到目前为止所有答案都可能比我的解决方案更好,但是它们都没有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()函数的不可预测的行为,那么更多的不确定性呢?对于在家中跟随的人来说,更快速地附加到文件似乎会导致它停止双重更新但老实说,我真的不知道,并且我对这个解决方案的行为感到满意,在实际情况下它会使用,这是一个单行文件,将以最快的速度每秒更新两次(更换内容)。

另一答案

我的定制解决方案

我个人喜欢使用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);
};

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

另一答案

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

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

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

以上是关于当我更改监视文件时,fs.watch会两次触发的主要内容,如果未能解决你的问题,请参考以下文章

删除监视文件夹时的节点监视 EPERM

fs.watch 不和谐机器人上的自动重新加载命令

在目录上使用 fs.watch 似乎不会注意到添加的文件

选中的单选按钮已更改事件触发两次

Perl inotify2 每次文件修改触发两次

fs.watch 爬坑