专栏首页YuanXinNodeJS是如何监听文件的变化?

NodeJS是如何监听文件的变化?

Keywords: 操作系统差异、识别用户/编辑器操作、连续触发的优化、工程级 API。

概述

NodeJS 提供了 fs.watch / fs.watchFile 两种 API:

  • fs.watch: 推荐,可以监听文件夹。基于操作系统。
  • fs.watchFile: 只能监听指定文件。并且通过轮询检测文件变化,不能响应实时反馈。

一个监听指定文件夹的代码如下:

fs.watch(dir, { recursive: true }, (eventType, file) => {
    if (file && eventType === "change") {
        console.log(`${file} 已经改变`);
    }
});

跨平台优化

对于不同系统内核,比如 maxos,fs.watch 回调函数中的第一个参数,不会监听到 rename、delete 事件。因此,这不是一个工程级别的可用 api

文件 md5

某些开源软件,会将文件内容都清空后,再添加内容。而且保存过程中,可能会出现多个中间态。

对于文件更改的情况,检测内容的 md5 值,是个不错的方法。

let previousMD5 = "";
fs.watch("./whatever", (type, filename) => {
    if (!filename) {
        return;
    }

    const md5 = crypto.createHash("md5");
    const currentMD5 = md5
        .update(fs.readFileSync(filename).toString())
        .digest("hex");
    if (currentMD5 === previousMD5) {
        return;
    }

    previousMD5 = currentMD5;
    console.log(`${filename} is changed`);
});

事件频率控制

对于文件变更,不同的系统可能会触发多个不同的中间态。因此,借助 debounce 函数的思想,控制和修正回调事件的触发频率。

前面的代码修正为:

let previousMD5 = "";
let watchWait = false; //

fs.watch("./whatever", (type, filename) => {
    if (!filename || watchWait) {
        return;
    }

    //
    watchWait = setTimeout(() => {
        watchWait = false;
    }, 100);

    const md5 = crypto.createHash("md5");
    const currentMD5 = md5
        .update(fs.readFileSync(filename).toString())
        .digest("hex");
    if (currentMD5 === previousMD5) {
        return;
    }

    previousMD5 = currentMD5;
    console.log(`${filename} is changed`);
});

文件信息

对于常见的库来说,除了不信任原生 API、使用上述技巧外,很重要的是,都根据 fs.Stats 类的信息,自定义逻辑来判断文件状态,以此保证不同平台兼容性

下面是在 Node10 中,打印的文件状态信息:

Stats {
  dev: 16777222,
  mode: 33188,
  nlink: 1,
  uid: 501,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 6493141,
  size: 7,
  blocks: 8,
  atimeMs: 1567516873292.676,
  mtimeMs: 1567516873293.3867,
  ctimeMs: 1567516873293.3867,
  birthtimeMs: 1566547653640.1763,
  atime: 2019-09-03T13:21:13.293Z,
  mtime: 2019-09-03T13:21:13.293Z,
  ctime: 2019-09-03T13:21:13.293Z,
  birthtime: 2019-08-23T08:07:33.640Z }

通过文件信息的思路,就是在fs.stat()的回调函数中,进行逻辑处理:

// 判断文件是否写入完毕的操作
function awaitWriteFinish() {
    // ...省略
    fs.stat(
        fullPath,
        function(err, curStat) {
            // ...省略

            if (prevStat && curStat.size != prevStat.size) {
                this._pendingWrites[path].lastChange = now;
            }

            if (now - this._pendingWrites[path].lastChange >= threshold) {
                delete this._pendingWrites[path];
                awfEmit(null, curStat);
            } else {
                timeoutHandler = setTimeout(
                    awaitWriteFinish.bind(this, curStat),
                    this.options.awaitWriteFinish.pollInterval
                );
            }
        }.bind(this)
    );
    // ...省略
}

成熟的库

参考链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • NodeJS模块研究 - fs

    node 的fs文档密密麻麻的 api 非常多,毕竟全面支持对文件系统的操作。文档组织的很好,操作基本分为文件操作、目录操作、文件信息、流这个大方面,编程方式也...

    心谭博客
  • 剑指offer - 链表中倒数第k个结点 - JavaScript

    因为要求链表倒数第 k 个节点,也就是求正数第length - k个节点。整体过程如下:

    心谭博客
  • 标签应用和版本管理

    当一个代码仓库进过长时间的迭代,针对不同的时期和需求,必定会有不同的版本。而借助 Git 提供的标签功能,可以快捷方便地记录代码版本。无论什么时候,想取回某个版...

    心谭博客
  • Go并发编程之美-条件变量

    go语言类似Java JUC包也提供了一些列用于多线程之间进行同步的措施,比如低级的同步措施有 锁、CAS、原子变量操作类。相比Java来说go提供了独特的基于...

    加多
  • Go并发编程之美-条件变量

    go语言类似Java JUC包也提供了一些列用于多线程之间进行同步的措施,比如低级的同步措施有 锁、CAS、原子变量操作类。相比Java来说go提供了独特的基于...

    加多
  • 世上最强版本Openshift之初体验

    横向比较,Openshift在全球IT圈内,Forrester最新的报告认为从技术表现和市场表现看,Openshift 3.10是业内最好的容器云平台。

    魏新宇
  • 水产巨头遇上“互联网+”,马化腾提的通威股份如何实施?

    腾讯研究院高级研究员 刘金松 腾讯研究院助理研究员 王勐璇 腾讯研究院助理研究员 练紫嫣 前不久,在杭州举行的“互联网+数字经济”峰会上,小马哥在主题演...

    腾讯研究院
  • DIY网站统计:WordPress排除管理员评论及精准友链数的方法

    今天关注了一下网站统计,发现留言 1600+,想想肯定是把我自己的留言也算进去了,感觉太水了,不真实!另外友链数目也不对,明显是把所有链接都加进去了! ? 于是...

    张戈
  • SourceInsight-强大的代码编辑和浏览工具-中文教程

    Source Insight作为一款功能强大的代码编辑查看软件,网上教程很多,但是都侧重某一方面展开介绍,很少有比较系统的完整软件的介绍,写这篇文档的目的就是尝...

    ZONGLYN
  • linux学习第九篇:特殊权限set_uid,set_gid,stick_bit以及软连接文件,硬链接文件

    特殊权限set_uid 权限s即为set_uid(给一个文件设置set_uid权限的前提是这个文件是二进制可执行文件) [root@xie-02 ~]# ls ...

    用户1215343

扫码关注云+社区

领取腾讯云代金券