使用Nodejs的watch监视文件变动时,为什么新增一个文件会产生两个created事件?

使用Nodejs的watch监视文件变动时,为什么新增一个文件会产生两个created事件?

有人使用到watch吗?

4 回复

使用 Node.js 的 fs.watch 监视文件变动时,为什么新增一个文件会产生两个 created 事件?

问题背景

在使用 Node.js 的 fs.watchfs.watchFile 方法监视文件系统变动时,有时会遇到新增文件时触发两次 created 事件的情况。这种行为可能会导致一些意外的结果,特别是在需要对文件变动做出响应的应用中。

原因分析

fs.watch 是一个底层 API,它依赖于操作系统的文件系统通知机制。在某些操作系统(如 Windows)上,当一个新文件被创建时,操作系统可能会发送两次事件通知。这可能是由于操作系统的实现细节,导致 fs.watch 捕获了两次文件系统变动的通知。

示例代码

const fs = require('fs');
const path = require('path');

const directoryPath = path.join(__dirname, 'testDir');

// 创建目录(如果不存在)
if (!fs.existsSync(directoryPath)) {
    fs.mkdirSync(directoryPath);
}

// 使用 fs.watch 监视目录
const watcher = fs.watch(directoryPath, (eventType, filename) => {
    if (filename) {
        console.log(`Event type: ${eventType}`);
        console.log(`Filename: ${filename}`);
        
        if (eventType === 'rename' && filename.endsWith('.txt')) {
            console.log(`New file created: ${filename}`);
        }
    }
});

// 创建一个新的文本文件
setTimeout(() => {
    const filePath = path.join(directoryPath, 'newfile.txt');
    fs.writeFileSync(filePath, 'Hello World!');
}, 2000);

// 监视器将在一段时间后关闭
setTimeout(() => {
    watcher.close();
    console.log('Watcher closed.');
}, 5000);

解释

  1. 创建目录:首先确保测试目录存在。
  2. 启动监视器:使用 fs.watch 监视目录中的文件变动。
  3. 创建文件:在两秒后,在指定目录下创建一个新的文本文件。
  4. 关闭监视器:五秒后关闭监视器。

当你运行这段代码时,你会看到输出两次 Event type: renameFilename: newfile.txt。这是因为操作系统可能发送了两次事件通知。

替代方案

为了避免这个问题,可以考虑使用更高级别的库,如 chokidar,它提供了更好的跨平台支持和更稳定的文件系统事件处理。

const chokidar = require('chokidar');

const directoryPath = path.join(__dirname, 'testDir');

// 创建目录(如果不存在)
if (!fs.existsSync(directoryPath)) {
    fs.mkdirSync(directoryPath);
}

// 使用 chokidar 监视目录
const watcher = chokidar.watch(directoryPath, {
    ignored: /(^|[\/\\])\../, // 忽略隐藏文件
    persistent: true
});

watcher.on('add', path => {
    console.log(`File added: ${path}`);
});

// 创建一个新的文本文件
setTimeout(() => {
    const filePath = path.join(directoryPath, 'newfile.txt');
    fs.writeFileSync(filePath, 'Hello World!');
}, 2000);

// 监视器将在一段时间后关闭
setTimeout(() => {
    watcher.close();
    console.log('Watcher closed.');
}, 5000);

在这个替代方案中,chokidar 库可以更好地处理文件系统事件,避免重复的 created 事件。


貌似有平台兼容性的问题, 我讲不来, 直接看 StackOverflow: http://stackoverflow.com/questions/11080132/nodejs-filesystem-watch-throwing-event-twice-or-more-often 用模块吧, 我之前用过这个: https://github.com/paulmillr/chokidar

在使用Node.js的fs.watchfs.watchFile监视文件变动时,可能会遇到新增一个文件产生两个created事件的情况。这是因为不同的操作系统和文件系统处理文件创建的方式不同。

例如,在某些操作系统上(如Linux),当一个新文件被创建时,fs.watch可能首先触发一个rename事件,随后再触发一个created事件。而在其他情况下,可能会触发两次created事件。

如果你只想监听一次文件创建事件,可以考虑使用fs.promises.watch(Node.js 16.4.0+)或者第三方库如chokidar来实现更稳定和可靠的监控。

示例代码

使用原生 fs.watch 监控文件变动:

const fs = require('fs');
const path = require('path');

const directoryPath = path.join(__dirname, 'files');

fs.watch(directoryPath, (eventType, filename) => {
    if (filename) {
        console.log(`Event type is: ${eventType}`);
        console.log(`Filename: ${filename}`);
    }
});

使用 chokidar 库来避免重复事件:

npm install chokidar
const chokidar = require('chokidar');

const watcher = chokidar.watch('./files', {
    ignored: /(^|[\/\\])\../, // 忽略隐藏文件
    persistent: true
});

watcher.on('add', path => {
    console.log(`File ${path} has been added`);
});

watcher.on('ready', () => {
    console.log('Initial scan finished');
});

通过使用 chokidar,可以更好地处理文件系统变化,并减少重复事件的发生。

回到顶部