简体   繁体   English

递归查找目录中的文件

[英]Go find files in directory recursively

I want to find all files matching a specific pattern in a directory recursively (including subdirectories).我想递归地在目录(包括子目录)中找到与特定模式匹配的所有文件。 I wrote the code to do this:我写了代码来做到这一点:

libRegEx, e := regexp.Compile("^.+\\.(dylib)$")
if e != nil {
    log.Fatal(e)
}

files, err := ioutil.ReadDir("/usr/lib")
if err != nil {
    log.Fatal(err)
}

for _, f := range files {
    if libRegEx.MatchString(f.Name()) {
        println(f.Name())
    }
}

Unfortunately, it only searches in /usr/bin , but I also want to search for matches in its subdirectories.不幸的是,它只在/usr/bin搜索,但我也想在其子目录中搜索匹配项。 How can I achieve this?我怎样才能做到这一点? Thanks.谢谢。

The standard library's filepath package includes Walk for exactly this purpose: "Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root."标准库的文件filepath包包含Walk正是为了这个目的:“Walk 遍历以根为根的文件树,为树中的每个文件或目录调用 walkFn,包括根。” For example:例如:

libRegEx, e := regexp.Compile("^.+\\.(dylib)$")
if e != nil {
    log.Fatal(e)
}

e = filepath.Walk("/usr/lib", func(path string, info os.FileInfo, err error) error {
    if err == nil && libRegEx.MatchString(info.Name()) {
        println(info.Name())
    }
    return nil
})
if e != nil {
    log.Fatal(e)
}

Starting with Go 1.16 (Feb 2021), you can use filepath.WalkDir :从 Go 1.16(2021 年 2 月)开始,您可以使用filepath.WalkDir

package main

import (
   "io/fs"
   "path/filepath"
)

func walk(s string, d fs.DirEntry, e error) error {
   if e != nil { return e }
   if ! d.IsDir() {
      println(s)
   }
   return nil
}

func main() {
   filepath.WalkDir("..", walk)
}

https://golang.org/pkg/path/filepath#WalkDir https://golang.org/pkg/path/filepath#WalkDir

If you are looking for something that doesn't use walk, I found this project如果您正在寻找不使用步行的东西,我找到了这个项目

The main recursive algorithm seems effective despite using strings.尽管使用了字符串,但主要的递归算法似乎很有效。 It basically amounts to the below code and kinda reminds me of merge sort and other recursive algorithms:它基本上相当于下面的代码,有点让我想起归并排序和其他递归算法:

func processed(fileName string, processedDirectories []string) bool {
    for i := 0; i < len(processedDirectories); i++ {
        if processedDirectories[i] != fileName {
            continue
        }
        return true
    }
    return false
}

func listDirContents(path string, dirs []string) {
    files, _ := ioutil.ReadDir(path)

    for _, f := range files {
        var newPath string
        if path != "/" {
            newPath = fmt.Sprintf("%s/%s", path, f.Name())
        } else {
            newPath = fmt.Sprintf("%s%s", path, f.Name())
        }

        if f.IsDir() {
            if !processed(newPath, dirs) {
                dirs = append(dirs, newPath)
                listDirContents(newPath, dirs)
            }
        } else {
            fmt.Println(newPath)
        }
    }
}

That actually prints all found paths starting from the provided directory and includes all sub-directories.这实际上会打印从提供的目录开始的所有找到的路径,并包括所有子目录。 Therefor you would have to check if the path contains your target string instead of just printing the path with fmt.Println() statements.因此,您必须检查路径是否包含目标字符串,而不仅仅是使用fmt.Println()语句打印路径。

After trying it out vs the find command, it scanned my /home directory in about .8s... the find command found the same files but did it in about .3s (a full .5s faster than the above algorithm).在与find命令对比后,它在大约 0.8 秒内扫描了我的/home目录...... find命令找到了相同的文件,但在大约 0.3 秒内完成(比上述算法快 0.5 秒)。

You can use all the files in the directory using following code:您可以使用以下代码使用目录中的所有文件:

files, err := ioutil.ReadDir(dirPath)
check(err)

for _, file := range files {
    fmt.Println(dirPath + file.Name())
}

The code is using the io/ioutil package to read all the files in the given directory and then looping through them to print there names.代码使用io/ioutil包读取给定目录中的所有文件,然后循环遍历它们以打印名称。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM