简介
Watcher
是一个可以实时观测某个文件或文件夹变动的 Golang
包,在不使用文件系统事件的情况下。所以利用这个包可以使我们的跨平台工作更加连贯。
Example
官方示例
package main
import (
"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 main
import (
"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 string
var cmdArgs []string
if *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.Stdout
c.Stderr = os.Stderr
if 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() {
<-c
w.Close()
<-done
fmt.Println("watcher closed")
close(closed)
}()
go func() {
if *cmd != "" && *startcmd {
com := exec.Command(cmdName, cmdArgs...)
com.Stdin = os.Stdin
com.Stdout = os.Stdout
com.Stderr = os.Stderr
if 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
小结
具体的使用方法在官方文档已经写得很清楚,这里不再赘述,之后我们进行源码分析