Go语言学习#7-如何进行目录遍历


=Start=

缘由:

刚好最近在学习Go语言,所以想着看能不能学习一下如何用Go语言进行实现——目录遍历有哪些方法,以及相对的最佳实践,方便以后快速参考改写。

正文:

参考解答:

Go 语言中进行目录遍历的原生方法主要是以下3种:
filepath.Walk()
ioutil.ReadDir()
os.File.Readdir()

性能是越底层越高(上层其实是对底层API的封装)。


filepath.Walk()遍历根目录(root)下的文件树,为树中的每个文件或目录(包括根目录)调用walkFn。所有在访问文件和目录时出现的错误都由walkFn过滤。遍历按词法顺序进行,这使得输出是确定的,但对于非常大的目录来说,遍历可能是低效的。filepath.Walk()不会跟进符号链接。

package main

import (
    "flag"
    "fmt"
    "os"
    "path/filepath"
)

// https://rosettacode.org/wiki/Walk_a_directory/Recursively#Go

const (
    layout = "2006-01-02 15:04:05"
)

func VisitFile(fp string, fi os.FileInfo, err error) error {
    if err != nil {
        fmt.Println(err) // can't walk here,
        return nil       // but continue walking elsewhere
    }
    if fi.IsDir() {
        return nil // not a file.  ignore.
    }
    // 过滤输出内容
    matched, err := filepath.Match("*.txt", fi.Name())
    if err != nil {
        fmt.Println(err) // malformed pattern
        return err       // this is fatal.
    }
    if matched {
        // fmt.Println(fp)
        fmt.Printf("Name: %s, ModifyTime: %s, Size: %v\n", fp, fi.ModTime().Format(layout), fi.Size())
    }
    return nil
}

func main() {
    var path = flag.String("path", ".", "The path to traverse.")
    flag.Parse()

    filepath.Walk(*path, VisitFile)
}

 

filepath.Walk()会自动遍历子目录,但有些时候我们不希望这样,如果只想看当前目录,或手动指定某几级目录中的文件,这个时候,可以使用 ioutil.ReadDir 进行替代。

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    var path = flag.String("path", ".", "The path to traverse.")
    flag.Parse()

    files, err := ioutil.ReadDir(*path)
    if err != nil {
        log.Fatal(err)
    }

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

 

几个方法封装的一个演示和对比:

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"
)

// https://stackoverflow.com/questions/14668850/list-directory-in-go/49196644#49196644

func main() {
    var (
        root  string
        files []string
        err   error
    )

    // root = "/home/manigandan/Desktop/Manigandan/sample"
    root = "."
    // filepath.Walk
    files, err = FilePathWalkDir(root)
    if err != nil {
        panic(err)
    }
    // ioutil.ReadDir
    files, err = IOReadDir(root)
    if err != nil {
        panic(err)
    }
    //os.File.Readdir
    files, err = OSReadDir(root)
    if err != nil {
        panic(err)
    }

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

func FilePathWalkDir(root string) ([]string, error) {
    var files []string
    err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
        if !info.IsDir() {
            files = append(files, path)
        }
        return nil
    })
    return files, err
}

func IOReadDir(root string) ([]string, error) {
    var files []string
    fileInfo, err := ioutil.ReadDir(root)
    if err != nil {
        return files, err
    }

    for _, file := range fileInfo {
        files = append(files, file.Name())
    }
    return files, nil
}

func OSReadDir(root string) ([]string, error) {
    var files []string
    f, err := os.Open(root)
    if err != nil {
        return files, err
    }
    fileInfo, err := f.Readdir(-1)
    f.Close()
    if err != nil {
        return files, err
    }

    for _, file := range fileInfo {
        files = append(files, file.Name())
    }
    return files, nil
}

 

参考链接:

=END=


《 “Go语言学习#7-如何进行目录遍历” 》 有 2 条评论

  1. 这年头感觉弄独立博客的程序员越来越少了,能坚持写这么多年的人也越来越少了。
    Google寻找有效率的go遍历目录的方法发现这片文章,写得不错,感谢

    很少发评论,表示一下自己也需要更新一下自己的博客!!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注