From 91f5d232a915d5852519f91ee8aaec78afecc475 Mon Sep 17 00:00:00 2001 From: Yun Date: Mon, 4 May 2026 00:17:15 +0800 Subject: [PATCH] commit --- go.mod | 7 ++ go.sum | 4 + tmp/aaa.txt | 0 watchx.go | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 tmp/aaa.txt create mode 100644 watchx.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..010f5f9 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module code.yun.ink/pkg/watchx + +go 1.20 + +require github.com/fsnotify/fsnotify v1.7.0 + +require golang.org/x/sys v0.4.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ccd7ce9 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/tmp/aaa.txt b/tmp/aaa.txt new file mode 100644 index 0000000..e69de29 diff --git a/watchx.go b/watchx.go new file mode 100644 index 0000000..63fa4f0 --- /dev/null +++ b/watchx.go @@ -0,0 +1,214 @@ +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 {} +}