设计思路
- 跨平台兼容性:通过使用
fs.watch
和fs.watchFile
结合的方式,fs.watch
是基于操作系统的文件系统事件通知机制,不同系统实现不同,fs.watchFile
是轮询方式,在fs.watch
不稳定时作为备用。
- 性能优化:对于
fs.watch
,尽量利用其高效的事件驱动特性;对于fs.watchFile
,设置合理的轮询间隔,避免过于频繁的文件状态检查。
- 事件准确捕获与处理:定义清晰的事件类型(创建、修改、删除),并通过事件发射器(
EventEmitter
)将事件准确地传递给调用者。
核心代码实现
const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
class CustomFileSystemMonitor extends EventEmitter {
constructor(directory) {
super();
this.directory = directory;
this.fileStates = new Map();
this.initWatchers();
}
initWatchers() {
const watcher = fs.watch(this.directory, { recursive: true }, (eventType, filename) => {
if (eventType === 'change') {
const filePath = path.join(this.directory, filename);
if (fs.statSync(filePath).isFile()) {
this.emit('fileChanged', filePath);
}
} else if (eventType === 'rename') {
const oldFilePath = path.join(this.directory, filename);
if (this.fileStates.has(oldFilePath)) {
this.emit('fileDeleted', oldFilePath);
this.fileStates.delete(oldFilePath);
}
}
});
watcher.on('error', (err) => {
console.error('fs.watch error:', err);
this.fallbackWatch();
});
}
fallbackWatch() {
const files = fs.readdirSync(this.directory);
files.forEach((file) => {
const filePath = path.join(this.directory, file);
this.fileStates.set(filePath, fs.statSync(filePath).mtime);
fs.watchFile(filePath, { persistent: true, interval: 1000 }, (curr, prev) => {
if (curr.mtime.getTime()!== prev.mtime.getTime()) {
this.emit('fileChanged', filePath);
this.fileStates.set(filePath, curr.mtime);
}
});
});
setInterval(() => {
const newFiles = fs.readdirSync(this.directory);
newFiles.forEach((file) => {
const filePath = path.join(this.directory, file);
if (!this.fileStates.has(filePath)) {
this.emit('fileCreated', filePath);
this.fileStates.set(filePath, fs.statSync(filePath).mtime);
}
});
const keys = Array.from(this.fileStates.keys());
keys.forEach((filePath) => {
if (!newFiles.includes(path.basename(filePath))) {
this.emit('fileDeleted', filePath);
this.fileStates.delete(filePath);
}
});
}, 1000);
}
}
// 使用示例
const monitor = new CustomFileSystemMonitor(__dirname);
monitor.on('fileCreated', (filePath) => {
console.log('File created:', filePath);
});
monitor.on('fileChanged', (filePath) => {
console.log('File changed:', filePath);
});
monitor.on('fileDeleted', (filePath) => {
console.log('File deleted:', filePath);
});