英文:
Golang File/Directory Walker adding files multiple times
问题
所以我正在使用filepath.Walk
函数递归监视文件的更改。fsnotify
无法直接递归监视。我设置了一个Goroutine来监视更改,然后在Walk()
函数中将路径添加到监视器中。
func (w Watch) walkDirectories(fp string) {
error := filepath.Walk(fp, func(path string, info os.FileInfo, err error) error {
// 跳过文件
if info == nil {
log.Fatalf("wrong watcher package: %s", path)
}
if !info.IsDir() {
return nil
}
if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") {
return filepath.SkipDir
}
log.Println("filepath: ", filepath)
w.W.Add(path)
return err
})
log.Println("error: ", error)
}
我有一个自定义的结构体来保存一个Watcher,这样我就可以轻松地为它添加要监视的路径。你可以在这里看到它的使用:w.W.Add(path)
。一切都很好,只是顶级目录中的文件似乎被添加了两次到监视器中,或者至少我的假设是“与顶级目录下的目录级数一样多次”。我的目录结构如下:
.
├── README.md
├── languages.go
├── languages.json
├── librarymonitor.go
├── telemetryClient
└── testfiles
├── test.go
├── test.c
├── test.java
如果我更改testfiles目录中的文件,监视器会收到一次“通知”。如果我更改根目录中的文件,我会收到两次通知。有人能解释一下这是为什么吗?谢谢。
英文:
So I am using the filepath.Walk
function to monitor for changes in files recursively. fsnotify
can't do recursive out of the box. I set up a Goroutine to monitor for changes, and then I add the paths to the watcher in the Walk()
function.
func (w Watch) walkDirectories(fp string) {
error := filepath.Walk(fp, func(path string, info os.FileInfo, err error) error {
// skip files
if info == nil {
log.Fatalf("wrong watcher package: %s", path)
}
if !info.IsDir() {
return nil
}
if len(path) > 1 && strings.HasPrefix(filepath.Base(path), ".") {
return filepath.SkipDir
}
log.Println("filepath: ", filepath)
w.W.Add(path)
return err
})
log.Println("error: ", error)
}
I have a custom Struct that holds a Watcher, so that I can easily add paths for it to watch. You can see it being used here: w.W.Add(path)
. It all works great, except that files in the top level directory seem to be added twice to the watcher, or at least my hypothesis is "as many times as their are directory levels below the top level". My directory structure is such that:
.
├── README.md
├── languages.go
├── languages.json
├── librarymonitor.go
├── telemetryClient
└── testfiles
├── test.go
├── test.c
├── test.java
If I change a file in the testfiles directory, I get one "notification" from the watcher. If I change a file in the root, I get two. Can anyone shed light on this?
Thanks
答案1
得分: 1
请检查你的主要代码,这个代码运行良好(尝试The Go Playground):
package main
import (
"fmt"
"os"
"path/filepath"
"reflect"
"time"
)
func main() {
rootDir := ".."
pattern := "*"
dirs, err := GetDirectories(rootDir, pattern)
if err != nil {
panic(err)
}
ticker := time.NewTicker(1 * time.Second)
for i := 1; i < 10; i++ {
<-ticker.C
dirs2, err := GetDirectories(rootDir, pattern)
//fmt.Println(dirs2)
if err != nil {
panic(err)
}
if !reflect.DeepEqual(dirs, dirs2) {
fmt.Println("Dir Changed: ", len(dirs), len(dirs2))
dirs = dirs2
}
}
ticker.Stop()
fmt.Println("Done")
}
// 返回指定目录中与指定搜索模式匹配的子目录(包括其路径)的名称。
func GetDirectories(root, pattern string) ([]string, error) {
dirs := make([]string, 0, 144)
return dirs, filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if !fi.IsDir() {
return nil
}
matched, err := filepath.Match(pattern, fi.Name())
if err != nil {
return err
}
if !matched {
return nil
}
dirs = append(dirs, path)
return nil
})
}
示例输出(带有一个新目录):
Dir Changed: 16 17
Done
英文:
Check your main code, this works fine, (try The Go Playground):
<!-- language: lang-golang -->
package main
import (
"fmt"
"os"
"path/filepath"
"reflect"
"time"
)
func main() {
rootDir := ".."
pattern := "*"
dirs, err := GetDirectories(rootDir, pattern)
if err != nil {
panic(err)
}
ticker := time.NewTicker(1 * time.Second)
for i := 1; i < 10; i++ {
<-ticker.C
dirs2, err := GetDirectories(rootDir, pattern)
//fmt.Println(dirs2)
if err != nil {
panic(err)
}
if !reflect.DeepEqual(dirs, dirs2) {
fmt.Println("Dir Changed: ", len(dirs), len(dirs2))
dirs = dirs2
}
}
ticker.Stop()
fmt.Println("Done")
}
// Returns the names of the subdirectories (including their paths)
// that match the specified search pattern in the specified directory.
func GetDirectories(root, pattern string) ([]string, error) {
dirs := make([]string, 0, 144)
return dirs, filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if !fi.IsDir() {
return nil
}
matched, err := filepath.Match(pattern, fi.Name())
if err != nil {
return err
}
if !matched {
return nil
}
dirs = append(dirs, path)
return nil
})
}
Sample output ( with one new dir):
Dir Changed: 16 17
Done
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论