关于nodejs fs.watch监视文件变化的疑问!
发布于 8 年前 作者 caihuattkl 6568 次浏览 来自 问答

function checkFilesChanges() { let checkFileDirectories = ‘C:/images’; let oldFile=null; fs.watch(checkFileDirectories, (e, filename) => { if(e === ‘rename’) { oldFile=filename; console.log(oldFile,filename) } }) }

为什么我这段代码,我新增了一个文件,能监视到…但是如果我修改了文件 会执行2次,就修改以前的名称,修改之后的名称,都会返回来.怎么才能知道他是从哪个文件修改到哪个文件呢?

比如我从1.txt,修改名称为2.txt 效果写不出来啊!!!

4 回复

有朋友知道吗?

没朋友知道吗?

Note that on most platforms, ‘rename’ is emitted whenever a filename appears or disappears in the directory.

文档上说了的, 当一个文件出现或消失都会触发事件, 重命名就是"消失"->“出现”. 如果某一次触发事件的文件不存在那么它就是"重命名"的原文件, 加个判断即可

function checkFilesChanges() {
    let checkFileDirectories = './file';
    let oldFile = null;

    let rename = true
    fs.watch(checkFileDirectories, (e, filename) => {
        if (e === 'rename') {
            fs.stat(checkFileDirectories + '/' + filename, (err, status) => {
                if (err && err.code === 'ENOENT') {
                    rename = true;
                    oldFile = filename;
                    return;
                }

                if (rename) {
                    console.log(oldFile, filename);
                    rename = false;
                } else {
                    console.log(filename);
                }

            })
        }
    })
}

这是一个非常复杂的问题。因为rename实际是由两步操作组成的:
remove oldFile
create newFile
下面这段程序是为了说明区分 create/remove/update 这三种情况的:
var fs = require('fs');

fs.watch('.', (eventType, filename) => {
    switch(eventType) {
    case 'rename':
        if (fs.existsSync(filename))
            console.log('create', filename, fs.statSync(filename));
        else
            console.log('remove', filename);     // 文件都不存在了,也调用不了fs.statSync了
        break;
    case 'change':
        console.log('update', filename, fs.statSync(filename));
    }
});
增加 fs.statSync 是为了说明在 rename 操作发生后,ino项没有发生变化的是rename!!!
{ dev: 16777220,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 12932737,    // rename行为这项不变化,windows是不是这种情况呢?这需要你自己研究一下了。
  size: 399,
  blocks: 8,
  atime: 2017-05-14T03:41:01.000Z,
  mtime: 2017-05-14T03:41:01.000Z,
  ctime: 2017-05-14T03:41:01.000Z,
  birthtime: 2017-05-14T03:41:01.000Z }
rename = remove + create
因为remove事件发生后,无法调用fs.statSync了,所以进行比对也就变的困难了。
套用楼上方法,认为remove后紧跟create的就是rename,可以用下面代码:
var fs = require('fs');
var oldFile = undefined;
fs.watch('.', (eventType, filename) => {
    switch(eventType) {
    case 'rename':
        if (fs.existsSync(filename)) {
            if(oldFile) console.log('rename', oldFile, '->', filename);
			else console.log('create', filename);
			oldFile = undefined;
		}
        else {
            console.log('remove', filename);
			oldFile = filename;
		}
        break;
    case 'change':
        console.log('update', filename);
		oldFile = undefined;
    }
});
应该能适应大部分的情况吧。这样做还有问题遗留,就是事件是remove+rename!当接到remove事件时,谁知道后面是不是还跟着create事件呢?加个 timeout定时?50ms不来create就是remove,来了就是rename? 似乎也能对付过去。谁知道呢?!
测试结果表明,在跨目录rename时,事件出现次序是create+remove,因此这种方法走不通。
回到顶部