通过go遍历目录获取文件列表
Hello大家好呀,这次分享的内容是如何使用Go在文件系统中获取到文件夹中的所有文件列表。
本文将会列举三种方法
by Using:
filepath.Walk ioutil.ReadDir os.File.Readdir
使用filepath.Walk
path/filepath 标准库的包提供了便捷的Walk方法,它能自动的扫描子目录,使用起来也很简单
package main import ( "fmt" "os" "path/filepath" ) func main() { var files []string root := "/some/folder/to/scan" err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { files = append(files, path) return nil }) if err != nil { panic(err) } for _, file := range files { fmt.Println(file) } }
filepath.Walk 接受一个string指向根目录(root),和一个带有签名(signature)的函数类型WalkFunc
type WalkFunc func(path string, info os.FileInfo, err error) error
这个方法将会文件夹扫描的每一次遍历中被调用。
可以看到另一个变量info的类型是os.FileInfo,这个变量非常重要因为我们从当前的文件(文件夹或者是文件)获取很多有用的信息:文件名,文件大小,模式,更改时间
同时我们也可以避免去处理文件夹通过添加(下边的代码表示不处理文件夹)
if info.IsDir(){ return nil }
你还可以排除或者筛选出切片中的文件通过他们的拓展名,可以用filepath.Ext然后传文件路径进去(下边的代码表示不处理带.dat拓展名的文件)
if filepath.Ext(path) == '.dat'{ return nil }
我们可以存储文件名而非文件目录通过使用
files = append(files,info.Name())
我们也可以在一个单独的闭包中定义WalkFunc。我们只需要在visit中传递一个指向文件的指针:
package main import ( "fmt" "log" "os" "path/filepath" ) func visit(files *[]string) filepath.WalkFunc { return func(path string, info os.FileInfo, err error) error { if err != nil { log.Fatal(err) } *files = append(*files, path) return nil } } func main() { var files []string root := "/some/folder/to/scan" err := filepath.Walk(root, visit(&files)) if err != nil { panic(err) } for _, file := range files { fmt.Println(file) } }
使用ioutil.ReadDir
filepath.Walk是很方便但是它会扫描所有子文件夹,缺省情况下,但这有时候不是我们想要的需求
go的标准库还提供了ioutil.ReadDir
ioutil.ReadDir需要一个string类型的文件夹路径然后返回一个os.FileInfo的切片,在上文中提到过。
package main import ( "fmt" "io/ioutil" "log" ) func main() { files, err := ioutil.ReadDir(".") if err != nil { log.Fatal(err) } for _, file := range files { fmt.Println(file.Name()) } }
使用os.File.Readdir
ReadDir内部的实现方式
// ReadDir reads the directory named by dirname and returns // a list of directory entries sorted by filename. func ReadDir(dirname string) ([]os.FileInfo, error) { f, err := os.Open(dirname) if err != nil { return nil, err } list, err := f.Readdir(-1) f.Close() if err != nil { return nil, err } sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) return list, nil }
我们可以看到它只扫描文件夹目录,然后将文件通过名字排序。如果我们不需要这种排序我们可以这样:
package main import ( "fmt" "log" "os" ) func main() { dirname := "." f, err := os.Open(dirname) if err != nil { log.Fatal(err) } files, err := f.Readdir(-1) f.Close() if err != nil { log.Fatal(err) } for _, file := range files { fmt.Println(file.Name()) } }
可以看到我们拆解了原方法的部分,dirname我们可以自己传,只使用Readdir(-1)这个方法去遍历文件夹。说实话这个-1我不是很懂为什么可以这么传,如果有会的大神能不能评论解释一下。