使用Nodejs的watch监视文件变动时,为什么新增一个文件会产生两个created事件?
使用Nodejs的watch监视文件变动时,为什么新增一个文件会产生两个created事件?
有人使用到watch吗?
使用 Node.js 的 fs.watch
监视文件变动时,为什么新增一个文件会产生两个 created
事件?
问题背景
在使用 Node.js 的 fs.watch
或 fs.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);
解释
- 创建目录:首先确保测试目录存在。
- 启动监视器:使用
fs.watch
监视目录中的文件变动。 - 创建文件:在两秒后,在指定目录下创建一个新的文本文件。
- 关闭监视器:五秒后关闭监视器。
当你运行这段代码时,你会看到输出两次 Event type: rename
和 Filename: 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.watch
或fs.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
,可以更好地处理文件系统变化,并减少重复事件的发生。