当我更改监视文件时,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:
- 是unstable
- 有重复通知的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
}
}
我建议使用chokidar
(https://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监视操作系统活动,因此将拾取这些应用程序触发的所有事件。
第一个是改变,第二个是重命名
我们可以从监听器功能中有所作为
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会两次触发的主要内容,如果未能解决你的问题,请参考以下文章