Golang 监控文件夹内文件的增删改(包括子文件夹)
你需要自己处理log部分
package main import ( "crypto/md5" "fmt" "go-admin/log" "os" "path/filepath" "time" "github.com/fsnotify/fsnotify" ) type FileChangeCallback func(absfpname string) type ConfigFileWatcher struct { WatchedDirectory string // 监控目录 FileSuffix string // 监控的文件类型 OnFileChange FileChangeCallback // 相关文件有变更就会调用这个回调 } func (cfw ConfigFileWatcher) WatchConfigFileChanges() { // 注意如果该文件被其他程序占用的话会读取不出内容的。比如vscode打开了文件 getFileHash := func(filename string) (string, error) { data, err := os.ReadFile(filename) if err != nil { return "", err } return fmt.Sprintf("%x", md5.Sum(data)), nil } watcher, err := fsnotify.NewWatcher() if err != nil { log.Fatal("WatchConfigFileChanges", err.Error(), "") } defer watcher.Close() dir := cfw.WatchedDirectory fileInfos := make(map[string]string) err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { err = watcher.Add(path) if err != nil { log.Fatal("WatchConfigFileChanges", err.Error(), "") } } else { if filepath.Ext(path) == ".yml" { hash, err := getFileHash(path) if err != nil { log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error()) } else { fileInfos[path] = hash } } } return nil }) if err != nil { log.Fatal("WatchConfigFileChanges", "%s", err.Error()) } fmt.Println("开始监控...") var lastEventTime time.Time interval := 500 * time.Millisecond // 设置等待时间为500毫秒 func() { for { select { case event, ok := <-watcher.Events: if !ok { return } if (event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create) && filepath.Ext(event.Name) == cfw.FileSuffix { // 检查时间间隔,如果在等待时间内则跳过 if time.Since(lastEventTime) < interval { continue } // 获取文件的最新MD5值 newHash, err := getFileHash(event.Name) if err != nil { log.Fatal("WatchConfigFileChanges", "获取文件哈希出错:%s", err.Error()) } else { // 对比MD5值,确认文件内容是否发生了变化 if prevHash, exists := fileInfos[event.Name]; exists && prevHash == newHash { fmt.Println("文件未更改:", event.Name) log.Log("WatchConfigFileChanges", "文件未更改:%s", event.Name) } else { fileInfos[event.Name] = newHash absPath, _ := filepath.Abs(event.Name) log.Log("WatchConfigFileChanges", "文件修改或创建:%s", absPath) cfw.OnFileChange(absPath) } } // 更新最后事件时间 lastEventTime = time.Now() // 因为fsnotify源码常量定义错了。Rename和Remove搞反了 } else if (event.Op&fsnotify.Rename == fsnotify.Rename) && filepath.Ext(event.Name) == cfw.FileSuffix { // 检查时间间隔,如果在等待时间内则跳过 if time.Since(lastEventTime) < interval { continue } absPath, _ := filepath.Abs(event.Name) fmt.Println("文件被删除:", absPath) cfw.OnFileChange(absPath) // 更新最后事件时间 lastEventTime = time.Now() } case err, ok := <-watcher.Errors: if !ok { return } log.Fatal("WatchConfigFileChanges", "错误:%s", err.Error()) } } }() }