Liệt kê các tệp trong một thư mục với Go

Trong bài viết này, tôi giải thích cách lấy danh sách các tệp bên trong một thư mục trên hệ thống tệp, một tác vụ còn được gọi làđi ngang qua cây, với cờ vây.

Có hai hàm stdlib tiện dụng mà bạn có thể sử dụng tùy thuộc vào mục tiêu của mình.

Tôi liệt kê 3 cách: sử dụngfilepath.Walk,ioutil.ReadDirhoặc làos.File.Readdir.

Sử dụngfilepath.Walk

Cácpath/filepathgói stdlib cung cấp chức năng Đi bộ tiện dụng. Tuy nhiên, nó sẽ tự động quét các thư mục con, vì vậy hãy đảm bảo rằng đây là những gì bạn thực sự muốn.

Cách sử dụng rất đơn giản:

package main

import ( “fmt” “os” “path/filepath” )

func main() { var files []string

<span style="color:#a6e22e">root</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">"/some/folder/to/scan"</span>
<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">path</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">info</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">FileInfo</span>, <span style="color:#a6e22e">err</span> <span style="color:#66d9ef">error</span>) <span style="color:#66d9ef">error</span> {
    <span style="color:#a6e22e">files</span> = append(<span style="color:#a6e22e">files</span>, <span style="color:#a6e22e">path</span>)
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
})
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>)
}

}

filepath.Walkchấp nhận một chuỗi trỏ đến thư mục gốc vàWalkFunc, một loại chức năng có chữ ký

type WalkFunc func(path string, info os.FileInfo, err error) error

Hàm này được gọi cho mỗi lần quét thư mục lặp lại.

Cácinfobiến loạios.FileInforất quan trọng vì chúng tôi có thể nhận được nhiều thông tin về tệp hiện tại: tên, kích thước, chế độ, thời gian sửa đổi, nếu đó là một thư mục hay tệp và nguồn dữ liệu cơ bản.

Ví dụ: chúng tôi có thể tránh xử lý các thư mục bằng cách thêm

if info.IsDir() {
    return nil
}

Bạn có thể loại trừ (hoặc bao gồm) các tệp vào phần dựa trên phần mở rộng của chúng, bằng cách sử dụngfilepath.Extvà chuyển đường dẫn tệp:

if filepath.Ext(path) == ".dat" {
    return nil
}

Chúng tôi có thể lưu trữ tên tệp thay vì đường dẫn tệp bằng cách sử dụng

files = append(files, info.Name())

Và chúng tôi cũng có thể xác địnhWalkFunctrong một sự riêng biệtKhép kín. Chúng tôi chỉ cần chuyển một con trỏ đếnfilestrongvisit:

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

<span style="color:#a6e22e">root</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">"/some/folder/to/scan"</span>
<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#a6e22e">visit</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">files</span>))
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>)
}

}

Sử dụngioutil.ReadDir

filepath.Walkrất tiện dụng nhưng cũng quét các thư mục con theo mặc định, điều này có thể không như bạn muốn.

Go stdlib cũng cung cấpioutil.ReadDir

func ReadDir(dirname string) ([]os.FileInfo, error)

ReadDir đọc thư mục có tên dirname và trả về danh sách các mục nhập thư mục được sắp xếp theo tên tệp.

và đây là một ví dụ từ tài liệu.ioutil.ReadDirlấy một đường dẫn thư mục dưới dạng một chuỗi và trả về một phần củaos.FileInfo, mà chúng tôi đã mô tả ở trên.

package main

import ( “fmt” “io/ioutil” “log” )

func main() { files, err := ioutil.ReadDir(".") if err != nil { log.Fatal(err) }

<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Name</span>())
}

}

Sử dụngos.File.Readdir

Trong nội bộ,ioutil.ReadDirđược thực hiện như

// 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
}

như bạn có thể thấy nó quétdirnamevà sắp xếp các tệp theo tên. Nếu bạn không cần phân loại, bạn cũng có thể sử dụng

package main

import ( “fmt” “log” “os” )

func main() { dirname := “.”

<span style="color:#a6e22e">f</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#a6e22e">dirname</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
}
<span style="color:#a6e22e">files</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Readdir</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)
<span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Close</span>()
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
}

<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Name</span>())
}

}


Các hướng dẫn về go khác: