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

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

    官方文档:https://godoc.org/github.com/fsnotify/fsnotify

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

    下面简单介绍其使用。

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

    1. package main
    2. import (
    3. "log"
    4. "github.com/fsnotify/fsnotify"
    5. )
    6. func main() {
    7. watcher, err := fsnotify.NewWatcher()
    8. if err != nil {
    9. log.Fatal(err)
    10. }
    11. defer watcher.Close()
    12. done := make(chan bool)
    13. go func() {
    14. for {
    15. select {
    16. case event, ok := <-watcher.Events:
    17. if !ok {
    18. return
    19. }
    20. log.Println("event:", event)
    21. if event.Op&fsnotify.Write == fsnotify.Write {
    22. log.Println("modified file:", event.Name)
    23. }
    24. case err, ok := <-watcher.Errors:
    25. if !ok {
    26. return
    27. }
    28. log.Println("error:", err)
    29. }
    30. }
    31. }()
    32. err = watcher.Add("E:\\test")
    33. if err != nil {
    34. log.Fatal(err)
    35. }
    36. <-done
    37. }

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

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

    其事件类型如下:

    1. type Event struct {
    2. Name string // Relative path to the file or directory.
    3. Op Op // File operation that triggered the event.
    4. }

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

    1. const (
    2. Create Op = 1 << iota
    3. Write
    4. Remove
    5. Rename
    6. Chmod
    7. )

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

    1. package main
    2. import (
    3. "log"
    4. "os"
    5. "path/filepath"
    6. "github.com/fsnotify/fsnotify"
    7. )
    8. func watchDir(watcher *fsnotify.Watcher,dir string) {
    9. // 遍历子目录
    10. filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
    11. // 判断是否为目录,只需要监听目录,目录下的文件变化就可以进行相应操作
    12. if info.IsDir(){
    13. path, err := filepath.Abs(path)
    14. if err != nil {
    15. log.Println(err)
    16. return err
    17. }
    18. // 然后将其加入监听
    19. if err := watcher.Add(path);err!=nil{
    20. log.Printf("watch %s failed. err = %s",path,err.Error())
    21. return err
    22. }
    23. }
    24. return nil
    25. })
    26. }
    27. func main() {
    28. watcher, err := fsnotify.NewWatcher()
    29. if err != nil {
    30. log.Fatal(err)
    31. }
    32. defer watcher.Close()
    33. done := make(chan bool)
    34. go func() {
    35. for {
    36. select {
    37. case event, ok := <-watcher.Events:
    38. if !ok {
    39. return
    40. }
    41. log.Println("event:", event)
    42. if event.Op&fsnotify.Write == fsnotify.Write {
    43. log.Println("modified file:", event.Name)
    44. }
    45. if event.Op&fsnotify.Create != 0{
    46. log.Println("Created file:", event.Name)
    47. }
    48. case err, ok := <-watcher.Errors:
    49. if !ok {
    50. return
    51. }
    52. log.Println("error:", err)
    53. }
    54. }
    55. }()
    56. //err = watcher.Add("E:\\test")
    57. //if err != nil {
    58. // log.Fatal(err)
    59. //}
    60. watchDir(watcher,"E:\\test")
    61. <-done
    62. }

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