Golang 监控文件夹内文件的增删改(包括子文件夹)

发布时间 2024-01-11 09:10:52作者: 看一百次夜空里的深蓝
  1 package main
  2 
  3 import (
  4     "crypto/md5"
  5     "fmt"
  6     "go-admin/log"
  7     "os"
  8     "path/filepath"
  9     "time"
 10 
 11     "github.com/fsnotify/fsnotify"
 12 )
 13 
 14 type FileChangeCallback func(absfpname string)
 15 
 16 type ConfigFileWatcher struct {
 17     WatchedDirectory string             // 监控目录
 18     FileSuffix       string             // 监控的文件类型
 19     OnFileChange     FileChangeCallback // 相关文件有变更就会调用这个回调
 20 }
 21 
 22 func (cfw ConfigFileWatcher) WatchConfigFileChanges() {
 23     // 注意如果该文件被其他程序占用的话会读取不出内容的。比如vscode打开了文件
 24     getFileHash := func(filename string) (string, error) {
 25         data, err := os.ReadFile(filename)
 26         if err != nil {
 27             return "", err
 28         }
 29         return fmt.Sprintf("%x", md5.Sum(data)), nil
 30     }
 31 
 32     watcher, err := fsnotify.NewWatcher()
 33     if err != nil {
 34         log.Fatal("WatchConfigFileChanges", err.Error(), "")
 35     }
 36     defer watcher.Close()
 37 
 38     dir := cfw.WatchedDirectory
 39 
 40     fileInfos := make(map[string]string)
 41 
 42     err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
 43         if err != nil {
 44             return err
 45         }
 46         if info.IsDir() {
 47             err = watcher.Add(path)
 48             if err != nil {
 49                 log.Fatal("WatchConfigFileChanges", err.Error(), "")
 50             }
 51         } else {
 52             hash, err := getFileHash(path)
 53             if err != nil {
 54                 log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error())
 55             } else {
 56                 fileInfos[path] = hash
 57             }
 58         }
 59         return nil
 60     })
 61     if err != nil {
 62         log.Fatal("WatchConfigFileChanges", "%s", err.Error())
 63 
 64     }
 65 
 66     fmt.Println("开始监控...")
 67 
 68     var lastEventTime time.Time
 69     interval := 500 * time.Millisecond // 设置等待时间为500毫秒
 70 
 71     func() {
 72         for {
 73             select {
 74             case event, ok := <-watcher.Events:
 75                 if !ok {
 76                     return
 77                 }
 78                 if (event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create) &&
 79                     filepath.Ext(event.Name) == cfw.FileSuffix {
 80 
 81                     // 检查时间间隔,如果在等待时间内则跳过
 82                     if time.Since(lastEventTime) < interval {
 83                         continue
 84                     }
 85 
 86                     // 获取文件的最新MD5值
 87                     newHash, err := getFileHash(event.Name)
 88                     if err != nil {
 89                         log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error())
 90                     } else {
 91                         // 对比MD5值,确认文件内容是否发生了变化
 92                         if prevHash, exists := fileInfos[event.Name]; exists && prevHash == newHash {
 93                             fmt.Println("文件未更改:", event.Name)
 94                             log.Log("WatchConfigFileChanges", "文件未更改:%s", event.Name)
 95                         } else {
 96                             fileInfos[event.Name] = newHash
 97                             absPath, _ := filepath.Abs(event.Name)
 98                             log.Log("WatchConfigFileChanges", "文件修改或创建:%s", absPath)
 99                             cfw.OnFileChange(absPath)
100                         }
101                     }
102 
103                     // 更新最后事件时间
104                     lastEventTime = time.Now()
105 
106                     // 因为fsnotify源码常量定义错了。Rename和Remove搞反了
107                 } else if (event.Op&fsnotify.Rename == fsnotify.Rename) && filepath.Ext(event.Name) == cfw.FileSuffix {
108                     // 检查时间间隔,如果在等待时间内则跳过
109                     if time.Since(lastEventTime) < interval {
110                         continue
111                     }
112                     absPath, _ := filepath.Abs(event.Name)
113                     fmt.Println("文件被删除:", absPath)
114                     cfw.OnFileChange(absPath)
115                     // 更新最后事件时间
116                     lastEventTime = time.Now()
117                 }
118             case err, ok := <-watcher.Errors:
119                 if !ok {
120                     return
121                 }
122                 log.Fatal("WatchConfigFileChanges", "错误:%s", err.Error())
123             }
124         }
125     }()
126 
127 }