简介
Watcher 是一个可以实时观测某个文件或文件夹变动的 Golang 包,在不使用文件系统事件的情况下。所以利用这个包可以使我们的跨平台工作更加连贯。
Example
官方示例
package mainimport ("fmt""log""time""github.com/radovskyb/watcher")func main() {w := watcher.New()w.SetMaxEvents(1)w.FilterOps(watcher.Rename, watcher.Move)go func() {for {select {case event := <-w.Event:fmt.Println(event)case err := <-w.Error:log.Fatalln(err)case <-w.Closed:return}}}()if err := w.Add("."); err != nil {log.Fatalln(err)}if err := w.AddRecursive("../test_folder"); err != nil {log.Fatalln(err)}for path, f := range w.WatchedFiles() {fmt.Printf("%s: %s\n", path, f.Name())}fmt.Println()go func() {w.Wait()w.TriggerEvent(watcher.Create, nil)w.TriggerEvent(watcher.Remove, nil)}()if err := w.Start(time.Millisecond * 100); err != nil {log.Fatalln(err)}}
运行结果

官方示例(Command)
package mainimport ("flag""fmt""log""os""os/exec""os/signal""strings""time""unicode""github.com/radovskyb/watcher")func main() {interval := flag.String("interval", "100ms", "watcher poll interval")recursive := flag.Bool("recursive", true, "watch folders recursively")dotfiles := flag.Bool("dotfiles", true, "watch dot files")cmd := flag.String("cmd", "", "command to run when an event occurs")startcmd := flag.Bool("startcmd", false, "run the command when watcher starts")listFiles := flag.Bool("list", false, "list watched files on start")stdinPipe := flag.Bool("pipe", false, "pipe event's info to command's stdin")keepalive := flag.Bool("keepalive", false, "keep alive when a cmd returns code != 0")flag.Parse()files := flag.Args()if len(files) == 0 {curDir, err := os.Getwd()if err != nil {log.Fatalln(err)}files = append(files, curDir)}var cmdName stringvar cmdArgs []stringif *cmd != "" {split := strings.FieldsFunc(*cmd, unicode.IsSpace)cmdName = split[0]if len(split) > 1 {cmdArgs = split[1:]}}w := watcher.New()w.IgnoreHiddenFiles(*dotfiles)done := make(chan struct{})go func() {defer close(done)for {select {case event := <-w.Event:fmt.Println(event)if *cmd != "" {c := exec.Command(cmdName, cmdArgs...)if *stdinPipe {c.Stdin = strings.NewReader(event.String())} else {c.Stdin = os.Stdin}c.Stdout = os.Stdoutc.Stderr = os.Stderrif err := c.Run(); err != nil {if !c.ProcessState.Success() && *keepalive {log.Println(err)continue}log.Fatalln(err)}}case err := <-w.Error:if err == watcher.ErrWatchedFileDeleted {fmt.Println(err)continue}log.Fatalln(err)case <-w.Closed:return}}}()for _, file := range files {if *recursive {if err := w.AddRecursive(file); err != nil {log.Fatalln(err)}} else {if err := w.Add(file); err != nil {log.Fatalln(err)}}}if *listFiles {for path, f := range w.WatchedFiles() {fmt.Printf("%s: %s\n", path, f.Name())}fmt.Println()}fmt.Printf("Watching %d files\n", len(w.WatchedFiles()))parsedInterval, err := time.ParseDuration(*interval)if err != nil {log.Fatalln(err)}closed := make(chan struct{})c := make(chan os.Signal)signal.Notify(c, os.Kill, os.Interrupt)go func() {<-cw.Close()<-donefmt.Println("watcher closed")close(closed)}()go func() {if *cmd != "" && *startcmd {com := exec.Command(cmdName, cmdArgs...)com.Stdin = os.Stdincom.Stdout = os.Stdoutcom.Stderr = os.Stderrif err := com.Run(); err != nil {log.Fatalln(err)}}}()if err := w.Start(parsedInterval); err != nil {log.Fatalln(err)}<-closed}
运行结果
./watcher
./watcher -list
试试进行文件改动
运行 wacher 后在另一个终端 touch Newfile
不出所料,检测到了变化
再试试删除命令 rm ./Newfile
再试试其他的, touch Newfile | mv Newfile Changed
小结
具体的使用方法在官方文档已经写得很清楚,这里不再赘述,之后我们进行源码分析
