在Go中使用fsnotify监听文件或者目录

·  阅读 44

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天。

在Linux中,我们知道有一个inotify的软件,它可以监听文件或者目录的变化,我们可以根据变化做不同的操作。

现在有一个Golang开发的工具也有这个功能,叫做fsnotify。

官方文档:godoc.org/github.com/…

从官方文档看其实现流程很简单,就只有三个结构体,一个监听,一个获取事件,一个处理。

下面简单介绍其使用。

我们先看官方的一个例子:

package main

import (
	"log"

	"github.com/fsnotify/fsnotify"
)

func main() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				log.Println("error:", err)
			}
		}
	}()

	err = watcher.Add("E:\\test")
	if err != nil {
		log.Fatal(err)
	}
	<-done
}
复制代码

然后我们创建一个测试文件,看日志输出如下: image.png 其使用比较简单:

  • 调用NewWatcher创建一个监听器
  • 调用监听器的Add方法增加监听的文件或目录
  • 同时会起一个协程不断获取监听事件,然后根据监听事件做不同的操作

其事件类型如下:

type Event struct {
    Name string // Relative path to the file or directory.
    Op   Op     // File operation that triggered the event.
}
复制代码

该类型只有两个字段,Name表示发生事件的文件名或目录,Op表示具体的事件。其中Op中有5个值,如下:

const (
    Create Op  = 1 << iota
    Write
    Remove
    Rename
    Chmod
)
复制代码

上面是监听单个目录或者文件,如果要监听目录及其子目录的话,就需要自己实现了,如下:

package main

import (
	"log"
	"os"
	"path/filepath"

	"github.com/fsnotify/fsnotify"
)

func watchDir(watcher *fsnotify.Watcher,dir string)  {
	// 遍历子目录
	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		// 判断是否为目录,只需要监听目录,目录下的文件变化就可以进行相应操作
		if info.IsDir(){
			path, err := filepath.Abs(path)
			if err != nil {
				log.Println(err)
				return err
			}
			// 然后将其加入监听
			if err := watcher.Add(path);err!=nil{
				log.Printf("watch %s failed. err = %s",path,err.Error())
				return err
			}
		}

		return nil
	})
}

func main() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case event, ok := <-watcher.Events:
				if !ok {
					return
				}
				log.Println("event:", event)
				if event.Op&fsnotify.Write == fsnotify.Write {
					log.Println("modified file:", event.Name)
				}
				if event.Op&fsnotify.Create != 0{
					log.Println("Created file:", event.Name)
				}
			case err, ok := <-watcher.Errors:
				if !ok {
					return
				}
				log.Println("error:", err)
			}
		}
	}()

	//err = watcher.Add("E:\\test")
	//if err != nil {
	//	log.Fatal(err)
	//}
	watchDir(watcher,"E:\\test")
	<-done
}
复制代码

然后我们操作子目录,也会有相应的事件发生。 image.png

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改