3

极简 Node.js 入门 - 3.5 监视文件变化

 2 years ago
source link: https://www.cnblogs.com/dolphinX/p/13594292.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node

本文更佳阅读体验:https://www.yuque.com/sunluyong/node/fs-watch

fs.FSWatcher

fs.FSWatcher类 继承了 EventEmitter,用于监视文件变化,调用 fs.watch 后返回一个 fs.FSWatcher 实例,每当指定监视的文件被修改时,实例会触发事件调用回调函数

fs.watch('./tmp', (eventType, filename) => {
  if (filename) {
    console.log(filename);
  }
});

fs.watch()

fs.watch(filename[, options][, listener]) 监视文件变化,返回 fs.FSWatcher 实例

  1. filename:文件或文件夹路径
  2. options
    • encoding
    • recursive:默认值 false,应该监视所有子目录,还是仅监视当前目录,仅在 macOS 和 Windows 上支持
    • persistent:默认值 true,指示如果文件已正被监视,进程是否应继续运行
    • listener(eventType, filename):文件变化回调函数

eventType 主要是 renamechange ,在大多数平台上,文件在目录中出现或消失时触发 'rename' 事件,在 Windows 上,如果监视的目录被移动或重命名,则不会触发任何事件,当监视的目录被删除时,则报告 EPERM 错误

fs.watch('./', { recursive: true }, (eventType, filename) => {
  console.log(eventType, filename);
});

fs.watchFile()

fs.watchFile(filename[, options], listener) 用于监视文件变化

  1. filename
  2. options
    • biginit:默认值 false,指定回调 stat 中的数值是否为 biginit 类型
    • persistent:默认值 true,当文件正在被监视时,进程是否应该继续运行
    • interval:默认值 5007,用来指定轮询频率(ms)
  3. listener(currentStats, previousStats):listener 有两个参数,当前的 stat 对象和之前的 stat 对象

要在修改文件时收到通知,则需要比较 curr.mtime 和 prev.mtime

const fs = require('fs');

fs.watchFile('./test.txt', { interval: 100 }, (curr, prev) => {
  console.log('当前的最近修改时间是: ' + curr.mtime);
  console.log('之前的最近修改时间是: ' + prev.mtime);
});

const tid = setInterval(() => {
  fs.appendFile('./test.txt', 'Hello, world!\n', err => {
    if (err) throw err;
    console.log('文件修改完成');
  });
}, 300);

setTimeout(() => {
  clearInterval(tid);
  fs.unwatchFile('./test.txt');
}, 2000);

fs.watch() 与 fs.watchFile()

因为 fs.watchFile() 使用轮训方式检测文件变化,如果不设置 interval 或者设置较高的值会发现文件变化的监视有延迟
而 fs.watch() 监听操作系统提供的事件,而且可以监视目录变化,使用 fs.watch() 比 fs.watchFile() 更高效,平常应尽可能使用 fs.watch() 代替 fs.watchFile()


当然 fs.watch() 依赖操作系统的实现,在不同平台上表现会有差异

  1. Linux 操作系统使用 inotify
  2. 在 macOS 系统使用 FSEvents
  3. 在 windows 系统使用 ReadDirectoryChangesW

fs.unwatchFile

fs.unwatchFile(filename[, listener]) 停止监视 filename 的变化,如果指定了 listener,则仅移除此特定监听器,否则将移除所有监听器,从而停止监视 filename

fs.unwatchFile('./test.txt');

fs.watchFile() 性能问题,fs.watch() 平台不一致等两个方法都有不尽如人意的地方

Node.js fs.watch:

  • MacOS 有时候不提供 filename
  • 在部分场景不触发修改事件(MacOS Sublime)
  • 经常一次修改两次触发事件
  • 大部分文件变化 eventType 都是 rename.
  • 未提供简单的监视文件树方式

Node.js fs.watchFile:

  • 事件处理问题和 fs.watch 一样烂
  • 没有嵌套监听
  • CPU 消耗大

https://www.npmjs.com/package/chokidar

日常在监视文件变化可以选择社区的优秀方案

const chokidar = require('chokidar');
 
// One-liner for current directory
chokidar.watch('.').on('all', (event, path) => {
  console.log(event, path);
});
// Initialize watcher.
const watcher = chokidar.watch('file, dir, glob, or array', {
  ignored: /(^|[\/\\])\../, // ignore dotfiles
  persistent: true
});
 
// Something to use when events are received.
const log = console.log.bind(console);
// Add event listeners.
watcher
  .on('add', path => log(`File ${path} has been added`))
  .on('change', path => log(`File ${path} has been changed`))
  .on('unlink', path => log(`File ${path} has been removed`));
 
// More possible events.
watcher
  .on('addDir', path => log(`Directory ${path} has been added`))
  .on('unlinkDir', path => log(`Directory ${path} has been removed`))
  .on('error', error => log(`Watcher error: ${error}`))
  .on('ready', () => log('Initial scan complete. Ready for changes'))
  .on('raw', (event, path, details) => { // internal
    log('Raw event info:', event, path, details);
  });

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK