去filepath.Walk挂起

时间:2017-08-31 16:18:54

标签: go

我在go中遇到了filepath.Walk()的奇怪问题。它开始运行然后到达它刚刚挂起的点。我的CPU处于100%,没有错误,也没有继续。我查看了我正在浏览的目录,它挂起的位置没什么特别的,没有symlins或类似的东西。只是简单的目录和文件。这是我使用的代码:

type WatchDirs struct {
    Dirs []string
}

//Watches ...Recursively walk the filesystem, entrypoint to file watching
func Watches(tops []string) error {
    var dirs WatchDirs
    for _, top := range tops {
        err := filepath.Walk(top, func(path string, f os.FileInfo, err error) error {
            if err != nil {
                log.Println(err)
                return err
            }
            log.Println("File: ", path)
            if f.IsDir() {
                //log.Println("Path: ", path)
                dirs.Dirs = append(dirs.Dirs, path)
            }
            return nil
        })
        if err != nil {
            log.Println(err)
        }
        log.Println("Continuing Loop")
    }
    log.Println("Starting Dedup: ")
    dirs.Dedup()
    log.Println("Post Dedup: ")
    for _, dir := range dirs.Dirs {
        log.Println(dir)
    }
    dirs.Watch()
    return nil
}

//Dedup ...Remove all duplicate entires from configured directories
func (dirs *WatchDirs) Dedup() {
    log.Println("deduping")
    uniqueSet := make(map[string]bool, len(dirs.Dirs))
    for _, x := range dirs.Dirs {
        uniqueSet[x] = true
    }
    result := make([]string, 0, len(uniqueSet))
    for x := range uniqueSet {
        result = append(result, x)
    }
    dirs.Dirs = result
}

//Watch ...Watch the list of created directories for changes
func (dirs *WatchDirs) Watch() {
    watcher, err := fsnotify.NewWatcher()
    if err != nil {
        log.Fatal(err)
    }
    defer watcher.Close()

    done := make(chan bool)
    go func() {
        for {
            select {
            case event := <-watcher.Events:
                log.Println("event:", event)
                if event.Op&fsnotify.Write == fsnotify.Write {
                    log.Println("modified file:", event.Name)
                }
            case err := <-watcher.Errors:
                log.Println("error:", err)
            }
        }
    }()

    for _, dir := range dirs.Dirs {
        log.Println("Watching dir: ", dir)
        err = watcher.Add(dir)
        if err != nil {
            log.Println(err)
        }
    }
    <-done
}

编辑:为了清晰起见,添加了其他功能。

1 个答案:

答案 0 :(得分:1)

我不是百分之百确定你的意图..然而,对我来说,宏计划似乎是想要将目录的路径附加到切片。您想检查是否添加了新内容,然后将该新目录添加到切片中。这是我的简单版本。每秒defined by the ticker我同步路径的位置。我使用信号来说,“嘿,我想停止观察更改并打印出所有路径”。我还使用一个通道来收听来自stdin的命令来做其他事情(你可以肯定地建立一些东西)。

我无法确切地告诉您原始代码中的失败点。如果您的watching有更改,那么除非您另有说明,否则代码应该是阻止的。

package main

import (
    "bufio"
    "io"
    "log"
    "os"
    "os/signal"
    "path/filepath"
    "syscall"
    "time"
)

type Watcher struct {
    Dirs    []DirInfo
    Ticker  *time.Ticker
    Stop    chan os.Signal
    Command chan string
}

type DirInfo struct {
    LastMod time.Time
    Path    string
}

func New() *Watcher {
    return &Watcher{
        Stop:    make(chan os.Signal, 1),
        Ticker:  time.NewTicker(1 * time.Second),
        Command: make(chan string),
    }
}

func (w *Watcher) addPath(path string, f os.FileInfo) {
    shouldAppend := true
    for i, d := range w.Dirs {
        if d.Path == path {
            w.Dirs[i].LastMod = f.ModTime()
            shouldAppend = false
            break
        }
    }
    if shouldAppend {
        w.Dirs = append(w.Dirs, DirInfo{f.ModTime(), path})
    }
}

func (w *Watcher) List() {
    if len(w.Dirs) == 0 {
        log.Println("Nothing to show")
        return
    }

    for _, d := range w.Dirs {
        log.Println(d.Path)
    }
    return
}

func (w *Watcher) isNew(path string, f os.FileInfo) bool {
    for _, d := range w.Dirs {
        if path == d.Path {
            t := f.ModTime()
            return t.After(d.LastMod)
        }
    }
    return true
}

func (w *Watcher) Sync(tops []string) {
    for _, top := range tops {
        err := filepath.Walk(top, func(path string, f os.FileInfo, err error) error {
            if err != nil {
                return err
            }
            if f.IsDir() && w.isNew(path, f) {
                w.addPath(path, f)
            }
            return nil
        })

        if err != nil {
            log.Printf("Error %v\n", err)
        }
    }
}


func main() {
    w := New()
    tops := []string{}

    signal.Notify(w.Stop, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        s := bufio.NewScanner(os.Stdin)

        for {
            for s.Scan() {
                w.Command <- s.Text()
            }
        }
    }()

    for {
        select {
        case <-w.Ticker.C:
            w.Sync(tops)
        case <-w.Stop:
            log.Println("signalled to stop")
            w.List()
            os.Exit(0)
        case cmd := <-w.Command:
            switch cmd {
            case "list":
                w.List()
            }
        }
    }

}