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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12978924/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:30:15  来源:igfitidea点击:

fs.watch fired twice when I change the watched file

node.jswindows-8watch

提问by avicennasoftwarelabs

 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:

输出:

  • some data
  • Done X 1
  • some data
  • Done X 2
  • 一些数据
  • 完成 X 1
  • 一些数据
  • 完成 X 2

It is my usage fault or ..?

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

回答by Pero P.

The fs.watchapi:

fs.watchAPI:

  1. is unstable
  2. has known "behaviour"with regards repeated notifications. Specifically, the windows casebeing a result of windows design, where a single file modification can be multiple calls to the windows API
  1. 不稳定
  2. 著名的“行为”与问候重复通知。具体来说,windows 案例是 windows 设计的结果,其中单个文件修改可以多次调用 windows API

回答by jwymanm

I make allowance for this by doing the following:

我通过执行以下操作来考虑到这一点:

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

回答by Artisan72

I suggest to work with chokidar(https://github.com/paulmillr/chokidar) which is much better than fs.watch:

我建议与chokidarhttps://github.com/paulmillr/chokidar)合作,这比fs.watch

Commenting its README.md:

评论它的 README.md:

Node.js fs.watch:

节点.js fs.watch

  • Doesn't report filenames on OS X.
  • Doesn't report events at all when using editors like Sublime on OS X.
  • Often reports events twice.
  • Emits most changes as rename.
  • Has a lot of other issues
  • Does not provide an easy way to recursively watch file trees.
  • 在 OS X 上不报告文件名。
  • 在 OS X 上使用 Sublime 等编辑器时根本不报告事件。
  • 经常报告事件两次。
  • 将大多数更改作为rename.
  • 很多其他问题
  • 不提供递归观察文件树的简单方法。

Node.js fs.watchFile:

节点.js fs.watchFile

  • Almost as bad at event handling.
  • Also does not provide any recursive watching.
  • Results in high CPU utilization.
  • 在事件处理方面几乎同样糟糕。
  • 也不提供任何递归监视。
  • 导致 CPU 使用率高。

回答by Jan ?wi?cki

If you need to watch your file for changes then you can check out my small library on-file-change. It checks file sha1 hash between fired changeevents.

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

Explanation of why we have multiple fired events:

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

You may notice in certain situations that a single creation event generates multiple Created events that are handled by your component. For example, if you use a FileSystemWatcher component to monitor the creation of new files in a directory, and then test it by using Notepad to create a file, you may see two Created events generated even though only a single file was created. This is because Notepad performs multiple file system actions during the writing process. Notepad writes to the disk in batches that create the content of the file and then the file attributes. Other applications may perform in the same manner. Because FileSystemWatcher monitors the operating system activities, all events that these applications fire will be picked up.

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

Source

来源

回答by Lasse Brustad

My custom solution

我的自定义解决方案

I personally like using returnto prevent a block of code to run when checking something, so, here is my method:

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

Feel free to use this example to simplify your code. It may NOTbe better than using a module from others, but it works pretty well!

随意使用此示例来简化您的代码。它可能不会比使用其他人的模块更好,但它工作得很好!

回答by Toadfish

I'm dealing with this issue for the first time, so all of the answers so far are probably better than my solution, however none of them were 100% suitable for my case so I came up with something slightly different – I used a XOR operation to flip an integer between 0 and 1, effectively keeping track of and ignoring every second event on the file:

我是第一次处理这个问题,所以到目前为止所有的答案都可能比我的解决方案更好,但是它们都不是 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;
}

I didn't want to use a time-related function (like jwymanm's answer) because the file I'm watching could hypothetically get legitimate updates very frequently. And I didn't want to use a list of watched files like Erik P suggests, because I'm only watching one file. Jan ?wi?cki's solution seemed like overkill, as I'm working on extremely short and simple files in a low-power environment. Lastly, Bernado's answer made me a little nervous – it would only ignore the second update if it arrived before I'd finished processing the first, and I can't handle that kind of uncertainty. If anyone were to find themselves in this very specific scenario, there might be some merit to the approach I used? If there's anything massively wrong with it please do let me know/edit this answer, but so far it seems to work well?

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

NOTE:Obviously this stronglyassumes that you'll get exactly 2 events per real change. I carefully tested this assumption, obviously, and learned its limitations. So far I've confirmed that:

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

  • Modifying a file in Atom editor and saving triggers 2 updates
  • touchtriggers 2 updates
  • Output redirection via >(overwriting file contents) triggers 2 updates
  • Appending via >>sometimes triggers 1 update!*
  • 在 Atom 编辑器中修改文件并保存会触发2 次更新
  • touch触发2 个更新
  • 输出重定向通过>(覆盖文件内容)触发2 个更新
  • 附加通过>>有时会触发 1 次更新!*

I can think of perfectly good reasons for the differing behaviours but we don't need to know whysomething is happening to plan for it – I just wanted to stress that you'll want to check for yourself in your own environment and in the context of your own use cases (duh) and not trust a self-confessed idiot on the internet. That being said, with precautions taken I haven't had any weirdness so far.

我可以为不同的行为想出非常好的理由,但我们不需要知道为什么会发生某些事情来为它做计划——我只是想强调你会想在你自己的环境和上下文中检查自己您自己的用例(废话),而不是相信互联网上自认的白痴。话虽如此,在采取预防措施的情况下,到目前为止我还没有任何奇怪之处。

*Full disclosure, I don't actually know why this is happening, but we're already dealing with unpredictable behaviour with the watch() function so what's a little more uncertainty? For anyone following along at home, more rapid appends to a file seem to cause it to stop double-updating but honestly, I don't really know, and I'm comfortable with the behaviour of this solution in the actual case it'll be used, which is a one-line file that will be updated (contents replaced) like twice per second at the fastest.

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

回答by liandong

first is change and the second is rename

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

we can make a difference from the listener function

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

function(event, filename) {

}

The listener callback gets two arguments (event, filename). event is either 'rename' or 'change', and filename is the name of the file which triggered the event.

侦听器回调有两个参数(事件、文件名)。event 是“rename”或“change”,filename 是触发事件的文件的名称。

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

as a sourcefile is renamed as targetfile, it's will call three event as fact

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

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

notice that , if you want catch all these three evnet, watch the dir of sourcefile

请注意,如果您想捕获所有这三个 evnet,请查看源文件的目录

回答by carlitoxenlaweb

Like others answers says... This got a lot of troubles, but i can deal with this in this way:

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

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

Hope can i help you...

希望我能帮到你...

回答by Arthur Araújo

Easiest solution:

最简单的解决方案:

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 () {
  // ...
})

回答by Erik P

I somtimes get multible registrations of the Watch event causing the Watch event to fire several times. I solved it by keeping a list of watching files and avoid registering the event if the file allready is in the list:

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

 var watchfiles = {};

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

......

......