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