英文:
How to set depth for recursive iteration of directories in filepath.walk() func in Golang?
问题
我想在一个包含多个子目录的目录中搜索特定类型的文件。我在Golang中使用filepath.walk()
来实现这个功能。然而,我不想递归迭代到超过我知道文件不存在的最大深度。
在Golang中是否有这样的预构建函数/库?
英文:
I want to search for a specific type of file inside a directory which has various sub-directories in it. I'm using filepath.walk()
in Golang for this. However, I don't want to iterate recursively beyond a max depth where I know that file can't exist.
Is there any such pre-built function/library in Golang?
答案1
得分: 4
首先,你应该使用Go 1.16中引入的filepath.WalkDir
,它比filepath.Walk
更高效。
> WalkDir比Walk更高效,它在访问每个文件或目录时避免了调用os.Lstat。
然后,没有直接的方法来指定最大深度作为参数。你需要在WalkDirFunc
中计算递归深度。
显然,在文件路径中计算分隔符的数量是一种可接受的策略(可能比其他可能的技巧更简单),因此解决方案可能如下所示:
maxDepth := 2
rootDir := "root"
err := filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
// 处理可能的路径错误,以防万一...
return err
}
if d.IsDir() && strings.Count(path, string(os.PathSeparator)) > maxDepth {
fmt.Println("跳过", path)
return fs.SkipDir
}
// ... 处理条目
return nil
})
因此,假设root
的深度为0
,上述代码将打印:
跳过 root/root1/root2/root3
跳过 root/root1/root2/root4
请注意,这只是翻译的代码部分,不包括任何其他内容。
英文:
First, you should use filepath.WalkDir
introduced in Go 1.16, which is more efficient than filepath.Walk
.
> Walk is less efficient than WalkDir, introduced in Go 1.16, which avoids calling os.Lstat on every visited file or directory.
Then, there is no way to specify the max depth as a direct argument. You have to compute the recursion depth in the WalkDirFunc
.
Apparently counting separators in the filepath is an acceptable strategy (and arguably simpler than other possible tricks), so the solution might look like:
maxDepth := 2
rootDir := "root"
err := filepath.WalkDir(rootDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
// handle possible path err, just in case...
return err
}
if d.IsDir() && strings.Count(path, string(os.PathSeparator)) > maxDepth {
fmt.Println("skip", path)
return fs.SkipDir
}
// ... process entry
return nil
})
So with dir structure as the following:
.
└── root
├── a.txt
├── b.txt
└── root1
├── a.txt
└── root2
├── a.txt
├── b.txt
├── root3
│   └── a.txt
└── root4
and assuming root
is at depth 0
, the above code the above code prints:
skip root/root1/root2/root3
skip root/root1/root2/root4
答案2
得分: -1
func ControlDeepWalk(basepath string, count int, hard, debug bool) error {
var (
stock = make(map[string][]string)
countBase = 0
correctdirs []string
)
base := filepath.Base(basepath)
dirbase := filepath.Dir(basepath)
countBase = len(strings.Split(filepath.Dir(basepath), "/"))
if debug {
log.Printf("countbase: %v %v\n", strings.Split(filepath.Dir(basepath), "/"), countBase)
log.Printf("base :%v : %v : %v\n", base, dirbase, strings.Split(basepath, "/"))
}
err := filepath.WalkDir(basepath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
if debug {
log.Printf("--error inf walkdir function, exit")
}
return err
}
if d.IsDir() {
if filepath.Dir(path) == filepath.Dir(basepath) {
if debug {
log.Printf("found root directory, skipping %v : %v\n", filepath.Dir(path), filepath.Dir(basepath))
}
} else {
compare := false
if hard {
compare = len(strings.Split(filepath.Dir(path), "/")) == countBase+count
} else {
compare = len(strings.Split(filepath.Dir(path), "/")) <= countBase+count
}
if compare {
if debug {
log.Printf("-found dir: [%v] %v\n", path, d.Name())
}
stock[filepath.Dir(filepath.Join(path, d.Name()))] = []string{}
correctdirs = append(correctdirs, filepath.Dir(filepath.Join(path, d.Name())))
}
}
} else {
fdir, ffile := filepath.Split(path)
for _, x := range correctdirs {
if x == filepath.Dir(fdir) {
if debug {
log.Printf("-found file:%v : %v %v %v \n", d.Name(), path, fdir, ffile)
}
stock[x] = append(stock[x], d.Name())
}
}
}
return nil
})
if debug {
for k, v := range stock {
log.Printf("%v : %v \n", k, v)
}
log.Printf("%v\n", stock)
}
return err
}
func main() {
p := "/backup/backuper/test"
count := 2
_ = ControlDeepWalk(p, count, false, true)
}
enjoy, dude! :)
英文:
func ControlDeepWalk(basepath string, count int, hard, debug bool) error {
var (
stock = make(map[string][]string)
countBase = 0
correctdirs []string
)
base := filepath.Base(basepath)
dirbase := filepath.Dir(basepath)
countBase = len(strings.Split(filepath.Dir(basepath), "/"))
if debug {
log.Printf("countbase: %v %v\n", strings.Split(filepath.Dir(basepath), "/"), countBase)
log.Printf("base :%v : %v : %v\n", base, dirbase, strings.Split(basepath, "/"))
}
err := filepath.WalkDir(basepath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
if debug {
log.Printf("--error inf walkdir function, exit")
}
return err
}
if d.IsDir() {
if filepath.Dir(path) == filepath.Dir(basepath) {
if debug {
log.Printf("found root directory, skipping %v : %v\n", filepath.Dir(path), filepath.Dir(basepath))
}
} else {
compare := false
if hard {
compare = len(strings.Split(filepath.Dir(path), "/")) == countBase+count
} else {
compare = len(strings.Split(filepath.Dir(path), "/")) <= countBase+count
}
if compare {
if debug {
log.Printf("-found dir: [%v] %v\n", path, d.Name())
}
stock[filepath.Dir(filepath.Join(path, d.Name()))] = []string{}
correctdirs = append(correctdirs, filepath.Dir(filepath.Join(path, d.Name())))
}
}
} else {
fdir, ffile := filepath.Split(path)
for _, x := range correctdirs {
if x == filepath.Dir(fdir) {
if debug {
log.Printf("-found file:%v : %v %v %v \n", d.Name(), path, fdir, ffile)
}
stock[x] = append(stock[x], d.Name())
}
}
}
return nil
})
if debug {
for k, v := range stock {
log.Printf("%v : %v \n", k, v)
}
log.Printf("%v\n", stock)
}
return err
}
func main() {
p := "/backup/backuper/test"
count := 2
_ = ControlDeepWalk(p, count, false, true)
}
enjoy, dude!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论