Source From Here
In this article I explain how to get a list of files inside a folder on the filesystem, a task also called tree traversing, with Go. There are two handy stdlib functions that you can use depending on your goal. I list 3 ways: using filepath.Walk, ioutil.ReadDir or os.File.Readdir.
Using filepath.Walk
The path/filepath stdlib package provides the handy Walk function. It automatically scans subdirectories, though, so make sure this is what you actually want.
Usage is very simple:
- 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)
- }
- }
- type WalkFunc func(path string, info os.FileInfo, err error) error
The info variable of type os.FileInfo is important because we can get many information on the current file: the name, size, mode, modification time, if it’s a folder or a file, and the underlying data source.
For example we could avoid processing folders by adding:
- if info.IsDir() {
- return nil
- }
- if filepath.Ext(path) == ".dat" {
- return nil
- }
- files = append(files, info.Name())
- 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)
- }
- }
filepath.Walk is handy but scans subfolders too, by default, which might not be what you want.
The Go stdlib also provides ioutil.ReadDir
- func ReadDir(dirname string) ([]os.FileInfo, error)
and here’s an example from the docs. ioutil.ReadDir takes a folder path as a string and returns a slice of os.FileInfo, which we described above.
- 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())
- }
- }
Internally, ioutil.ReadDir is implemented as:
- // 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())
- }
- }