通過go遍歷目錄獲取文件列表
Hello大家好呀怒炸,這次分享的內(nèi)容是如何使用Go在文件系統(tǒng)中獲取到文件夾中的所有文件列表差油。
本文將會列舉三種方法
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)的函數(shù)類型WalkFunc
type WalkFunc func(path string, info os.FileInfo, err error) error
這個方法將會文件夾掃描的每一次遍歷中被調(diào)用。
可以看到另一個變量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內(nèi)部的實現(xiàn)方式
// 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我不是很懂為什么可以這么傳,如果有會的大神能不能評論解釋一下蔗喂。