七爪源码:使用 NodeJs 观看文件系统

监视文件系统意味着监视特定目录或文件的更改 。

七爪源码:使用 NodeJs 观看文件系统

文章插图
 
有时您可能需要持续观察特定文件或目录的更改 。出于这个原因,我们使用像 chokidar 这样的文件系统 Watcher 或内置的 NodeJs 文件系统方法 fs.watch() 。
但是我们不会使用上面的方法,让我来告诉你这样做的原因 。
 
fs.watch()
fs 提供了一个应用程序编程接口 (API),可连续监视文件的更改 。可以使用此方法跟踪文件更改,该方法返回一个 fs.FSWatcher 对象 。在这里阅读更多关于它的信息 fs.watch() 。
缺点:
  • 这种方法不可靠,每次修改都可能在监听器中显示多个事件 。
  • 将大多数更改作为重命名发出 。
  • 不提供递归查看文件树的简单方法 。
  • 不报告 macOS 上的文件名 。
还有很多…
 
chokidar
它是最流行的文件系统观察器,但尽管在某些情况下它可能就足够了,但它并不完美 。
优点:
  • 它支持处理符号链接 。
  • 它有一些内置支持,可以在执行原子写入时处理写入磁盘的临时文件,尽管在 Watcher 中忽略它们也很简单,您可以通过忽略选项忽略它们 。
  • 它可以更可靠地观察网络连接的路径,尽管在观察大量文件时会导致性能问题 。
  • 尽管 Watcher(一个文件系统观察程序库,我们稍后会讨论)具有更全面的测试套件并且也用于生产(例如在 Notable 中,它之前使用了 chokidar),但它经过了更多的实战测试 。
缺点:
  • 它需要原生依赖才能在 macOS 下进行高效的递归观察,而原生依赖可能很难使用 。
  • 在 windows 下它不能有效地递归地观察,另一方面,Watcher(一个文件系统观察器库,我们将在后面讨论)是建立在 Node 的 Windows 原生递归观察能力之上的 。
  • 它无法检测重命名 。
  • 如果您不需要像 globbing 这样的功能,那么 chokidar 会不必要地膨胀您的应用程序包 。
  • EMFILE 错误没有得到正确处理,因此如果您观看的文件足够多,chokidar 最终会放弃它们 。
因为每种方法都有自己的缺点 。现在让我们来看看解决方案 。
【七爪源码:使用 NodeJs 观看文件系统】 
Watcher
一个追求完美的文件系统观察者,没有原生依赖和可选的重命名检测支持 。
我自己使用过这个库,与其他替代方案相比,我发现它非常简单且无错误 。
特征:
  1. 可靠:该库旨在处理处理文件系统时可能出现的所有问题,包括一些最流行的无法处理的替代方案,例如 EMFILE 错误 。
  2. 重命名检测:这个库可以选择性地检测文件和目录何时被重命名,这允许您在某些情况下为您的用户提供更好的体验 。
  3. 性能:在可用时使用本机递归监视(macOS 和 Windows),否则可以有效地手动执行 。
  4. 没有原生依赖:原生依赖使用起来会很痛苦,这个库使用了其中的 0 个 。
  5. 不臃肿:许多替代观察者附带可能无用且昂贵的功能,例如对通配的支持,这个库旨在更精简,同时仍然公开正确的抽象,让您可以根据需要使用通配 。
  6. TypeScript-ready:这个库是用 TypeScript 编写的,所以类型不是事后才想到的,而是随库一起提供的 。
您可以在此处查看与其他观察者的比较 。
安装:
npm install — save watcher
用法:
你会像这样使用这个库:
const Wattcher = require('watcher')// Watching a single pathconst watcher = new Watcher ( '/foo/bar' );// Watching multiple pathsconst watcher = new Watcher ( ['/foo/bar', '/baz/qux'] );// Passing some optionsconst watcher = new Watcher ( '/foo/bar', { renameDetection: true } );// Passing an "all" handler directlyconst watcher = new Watcher ( '/foo/bar', {}, ( event, targetPath, targetPathNext ) => {} );// Attaching the "all" handler manuallyconst watcher = new Watcher ( '/foo/bar' );watcher.on ( 'all', ( event, targetPath, targetPathNext ) => { // This is what the library does internally when you pass it a handler directlyconsole.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'console.log ( targetPath ); // => the file system path where the event took place, this is always providedconsole.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events});// Listening to individual events manuallyconst watcher = new Watcher ( '/foo/bar' );watcher.on ( 'error', error => {console.log ( error instanceof Error ); // => true, "Error" instances are always provided on "error"});watcher.on ( 'ready', () => {// The App just finished instantiation and may soon emit some events});watcher.on ( 'close', () => {// The app just stopped watching and will not emit any further events});watcher.on ( 'all', ( event, targetPath, targetPathNext ) => {console.log ( event ); // => could be any target event: 'add', 'addDir', 'change', 'rename', 'renameDir', 'unlink' or 'unlinkDir'console.log ( targetPath ); // => the file system path where the event took place, this is always providedconsole.log ( targetPathNext ); // => the file system path "targetPath" got renamed to, this is only provided on 'rename'/'renameDir' events});watcher.on ( 'add', filePath => {console.log ( filePath ); // "filePath" just got created, or discovered by the watcher if this is an initial event});watcher.on ( 'addDir', directoryPath => {console.log ( filePath ); // "directoryPath" just got created, or discovered by the watcher if this is an initial event});watcher.on ( 'change', filePath => {console.log ( filePath ); // "filePath" just got modified});watcher.on ( 'rename', ( filePath, filePathNext ) => {console.log ( filePath, filePathNext ); // "filePath" got renamed to "filePathNext"});watcher.on ( 'renameDir', ( directoryPath, directoryPathNext ) => {console.log ( directoryPath, directoryPathNext ); // "directoryPath" got renamed to "directoryPathNext"});watcher.on ( 'unlink', filePath => {console.log ( filePath ); // "filePath" got deleted, or at least moved outside the watched tree});watcher.on ( 'unlinkDir', directoryPath => {console.log ( directoryPath ); // "directoryPath" got deleted, or at least moved outside the watched tree});// Closing the watcher once you are done with itwatcher.close ();// Updating watched roots by closing a watcher and opening an updated onewatcher.close ();watcher = new Watcher ( /* Updated options... */ );


推荐阅读