go监视文件改变实现同步--包含遍历文件夹,执行cmd命令,检测文件改变
package main import ( "fmt" "time" "os/exec" "strings" "io/ioutil" "os" "github.com/howeyc/fsnotify" "sync" ) const ( filePath = "/home/ubuntu/GzhuOJ/public" hostname = "root@gzhuacm.cn" remotePath = "/home/public" ) var watcher *fsnotify.Watcher var mutex sync.Mutex func Print(args ...interface{}) { fmt.Println(time.Now(), args) } func isDir(path string) bool { fileInfo, err := os.Stat(path) if err != nil { Print("error:", err.Error()) return false } return fileInfo.IsDir() } func watchPath(filePath string) { Print("watchPath:", filePath) err := watcher.Watch(filePath) if err != nil { Print(err.Error()) return } } func broweDir(path string) { Print("broweDir:", path) dir, err := os.Open(path) if err != nil { Print("error:", err.Error()) return } defer dir.Close() names, err := dir.Readdirnames(-1) if err != nil { Print("error:", err.Error()) return } for _, name := range names { dirPath := path + "/" + name if !isDir(dirPath) { continue } watchPath(dirPath) broweDir(dirPath) } } func main() { var err error watcher, err = fsnotify.NewWatcher() if err != nil { panic(err) } defer watcher.Close() broweDir(filePath) watchPath(filePath) dealWatch() } func copy(event *fsnotify.FileEvent) *exec.Cmd { return exec.Command( "scp", "-r", "-P 23456", event.Name, hostname+":"+remotePath+strings.TrimPrefix(event.Name, filePath)) } func remove(event *fsnotify.FileEvent) *exec.Cmd { return exec.Command( "ssh", "-p 23456", hostname, `rm -r `+remotePath+strings.TrimPrefix(event.Name, filePath)+``) } func dealWatch() { for { func() { //mutex.Lock() //defer mutex.Unlock() select { case event := <-watcher.Event: Print("event: ", event) var cmd *exec.Cmd if event.IsCreate() || event.IsModify() { cmd = copy(event) } if event.IsDelete() || event.IsRename() { cmd = remove(event) } Print("cmd:", cmd.Args) stderr, err := cmd.StderrPipe() if err != nil { Print(err.Error()) return } defer stderr.Close() stdout, err := cmd.StdoutPipe() if err != nil { Print(err.Error()) return } defer stdout.Close() if err = cmd.Start(); err != nil { Print(err.Error()) return } errBytes, err := ioutil.ReadAll(stderr) if err != nil { Print(err.Error()) return } outBytes, err := ioutil.ReadAll(stdout) if err != nil { Print(err.Error()) return } if len(errBytes) != 0 { Print("errors:", string(errBytes)) } if len(outBytes) != 0 { Print("output:", string(outBytes)) } if err = cmd.Wait(); err != nil { Print(err.Error()) } case err := <-watcher.Error: Print("error: ", err.Error()) } }() } }
go cmd 的命令里不能ssh user@ip "rm /home/public" 最后的参数”/home/public"不要写引号("),不然会执行命令失败,但命令行里不加引号可以执行,所以尽量不要加引号
要注意的是一个fsnotify.Watcher能watch多个文件和文件夹,不要一个Watcher watch一个文件夹或文件,太多会报Too many open files