package main import ( "context" "fmt" "sync" // "log" "os" "path/filepath" "github.com/fsnotify/fsnotify" ) type Watch struct { ctx context.Context watch *fsnotify.Watcher mutex sync.Mutex // 保护watch状态的互斥锁 data chan Action // 文件列表 } type Action struct { Path string // 文件路径 Action string // } func NewWatch(ctx context.Context) (*Watch, error) { watch, err := fsnotify.NewWatcher() if err != nil { return nil, err } return &Watch{ ctx: ctx, watch: watch, data: make(chan Action), // 初始化文件列表 }, nil } // 添加路径到监控中候,需要加锁 func (w *Watch) addPath(path string, isDir bool) error { w.mutex.Lock() defer w.mutex.Unlock() if isDir { fmt.Println("文件夹:", path) } else { fmt.Println("文件:", path) } err := w.watch.Add(path) if err != nil { fmt.Printf("Error adding path %q: %v\n", path, err) return err } return nil } // 处理文件系统事件 func (w *Watch) handleEvent(ev fsnotify.Event) error { fmt.Println("event:", ev) if ev.Op&fsnotify.Create == fsnotify.Create { fmt.Println("创建文件:", ev.Name) w.addPath(ev.Name, false) w.data <- ev.Name } if ev.Op&fsnotify.Write == fsnotify.Write { fmt.Println("写入文件:", ev.Name) } if ev.Op&fsnotify.Remove == fsnotify.Remove { fmt.Println("删除文件:", ev.Name) w.watch.Remove(ev.Name) } if ev.Op&fsnotify.Rename == fsnotify.Rename { fmt.Println("重命名:", ev.Name) } if ev.Op&fsnotify.Chmod == fsnotify.Chmod { fmt.Println("修改权限:", ev.Name) } return nil } func (w *Watch) watchDir(dir string) error { err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { fmt.Printf("Error accessing path %q: %v\n", path, err) return err } if info.IsDir() { return w.addPath(path, true) } else { return w.addPath(path, false) } }) if err != nil { return err } go func() { defer w.watch.Close() // 确保Watcher在退出时被关闭 for { select { case ev := <-w.watch.Events: w.handleEvent(ev) case err := <-w.watch.Errors: fmt.Printf("error: %v\n", err) case <-w.ctx.Done(): // 接收到停止信号,退出goroutine return } } }() return nil } // 监控目录 func (w *Watch) watchDir2(dir string) error { // 通过Walk来遍历目录下的所有子目录 filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { fmt.Printf("Error accessing path %q: %v\n", path, err) return err } // 这里判断是否为目录,只需监控目录即可 // 目录下的文件也在监控范围内,不需要我们一个一个加 if info.IsDir() { path, err := filepath.Abs(path) if err != nil { panic(err) } err = w.watch.Add(path) if err != nil { return err } fmt.Println("文件夹:", path) } else { err = w.watch.Add(path) if err != nil { return err } fmt.Println("文件:", path) } return nil }) go func() { for { select { case ev := <-w.watch.Events: { fmt.Printf("ev %+v \n", ev) if ev.Op&fsnotify.Create == fsnotify.Create { fmt.Println("创建文件:", ev.Name) // 这里获取新创建文件的信息,如果是目录,则加入监控中 fi, err := os.Stat(ev.Name) if err == nil && fi.IsDir() { w.watch.Add(ev.Name) fmt.Println("添加监控:", ev.Name) } } if ev.Op&fsnotify.Write == fsnotify.Write { // 修改文件 fmt.Println("写入文件:", ev.Name) } if ev.Op&fsnotify.Remove == fsnotify.Remove { fmt.Println("删除文件:", ev.Name) // 如果删除文件是目录,则移除监控 // 注意这里无法使用os.Stat来判断是否是目录了 // 因为重命名后,go已经无法找到原文件来获取信息了 // 所以这里就简单粗暴的直接remove好了 w.watch.Remove(ev.Name) } if ev.Op&fsnotify.Rename == fsnotify.Rename { fmt.Println("重命名:", ev.Name) } if ev.Op&fsnotify.Chmod == fsnotify.Chmod { fmt.Println("修改权限:", ev.Name) } } case err := <-w.watch.Errors: { fmt.Println("error:", err) return } } } }() } func main() { w, err := NewWatch() if err != nil { fmt.Println(err) return } dirToWatch := "/log" err = w.watchDir(dirToWatch) if err != nil { fmt.Println(err) return } // 创建一个监控对象 select {} }