在Linux中,我们知道有一个inotify的软件,它可以监听文件或者目录的变化,我们可以根据变化做不同的操作。
现在有一个Golang开发的工具也有这个功能,叫做fsnotify。
官方文档:https://godoc.org/github.com/fsnotify/fsnotify
从官方文档看其实现流程很简单,就只有三个结构体,一个监听,一个获取事件,一个处理。
下面简单介绍其使用。
我们先看官方的一个例子:
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
}
然后我们创建一个测试文件,看日志输出如下:
其使用比较简单:
- 调用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
}
然后我们操作子目录,也会有相应的事件发生。