node 开发文件同步功能

163 阅读2分钟

一、功能场景

electron项目需要实时监听本地/线上文件变化进行差异比对同步文件,因而需要实时监听本地文件变化与线上文件进行比对

二、文件监听库

2.1 fs.watch和 fs.watchFil
watch 和watchFile存在一些系统兼容性问题,具体如下:
fs.watch:
  在 MacOS 上不报告文件名。
  在 MacOS 上使用像 Sublime 这样的编辑器时根本不报告事件。
  经常将事件报告两次。
  发出大多数变化作为rename.
  不提供递归查看文件树的简单方法。
  不支持 Linux 上的递归监视。
fs.watchFile:
  在事件处理方面几乎一样糟糕。
  也不提供任何递归监视。
  导致高 CPU 使用率。

所以选择 Chokidar 为文件监听库 ,Chokidar 库带有一下api:

all:        全部事件
add:        添加文件
addDir:    添加文件夹
change:    文件改变
unlink:    删除文件
unlinkDir: 删除文件夹

Chokidar 提供了一系列的api来反映文件的变化状态,但仍有两张种场景无法准确响应:1. 文件更名 2.文件移动

要解决这两种场景的改变目前有两种思路: 1. 文件更名或者移动的时候是先增加文件然后删除文件,我们可以根据文件操作的时间戳和文件的md5来判断是不是进行了更名或者移动操作。 2. 手动修改chokidar 库来增加这两种场景

三、实现思路

实现思路:

第一步:程序启动时获取本地文件和线上文件进行比对,从而确定那些文件是本地不存在的,即需要下载的文件,那些文件是线上不存在的,即需要上传的文件,比对完成之后分别进行上传和下载操作

将线上文件和本地文件转为格式相同的对象,文件通过md5,文件夹通过路径来比对是否一致,数据结构如下:
 fileObj = {
   1:[{name:'',path:''}.....],
   2:[{name:'',path''}.....],
 }
 将树形文件数据结构转为对象,同一层级打平为数组,这样操作的好处是当知道某一文件路径,就能快速的定位到文件在哪一层级,只需要循环一次就能查到这条数据,避免树形结构的递归查询

第二步:比对完成之后启动文件监听程序,即 Chokidar 程序,当文件发生变化时,通过api事件类型来区分不同的用户操作进行对应的文件处理

   addWatch() {
        let watcher = this.watcher
        if (watcher) {
            watcher.add(this.localPath);
        } else {
            watcher = chokidar.watch(this.localPath,{ignored: /(^|[/\])../});
            watcher.on("all", (event, path) => {
                //监听除了ready, raw, and error之外所有的事件类型
                console.log(event, path);
            });
            watcher.on("ready", (path) => {
                console.log("ready", path);
            });
            watcher.on("addDir", (path) => {
                console.log("addDir", path);
            });
            watcher.on("add", (path) => {
                 console.log("add", path);
            });
            watcher.on("change", (path) => {
                console.log("change", path);
            });
            watcher.on("unlink", (path) => {
               console.log("unlink", path);
            });
            watcher.on("unlinkDir", (path) => {
                console.log("unlinkDir", path);
            });
        }
    }
    
 根据不同的api进行不同的文件操作