hakk

software development, devops, and other drivel
Tree lined path

How to list files in a directory using Go [2023]

In Go there are a couple of options to list the files of a directory using the standard library. In this article you will find a list of three different methods.

Note: Be aware that ioutil.ReadDir is deprecated since Go 1.16. Instead os.ReadDir should be used (shown in this article).

os.ReadDir

os.ReadDir is included in the standard library in the os package. Check out the documentation for more information. It’s a drop in replacement from ioutil.ReadDir.

It returns a DirEntry which is an interface that looks like:

type DirEntry interface {
	// Name returns the name of the file (or subdirectory) described by the entry.
	// This name is only the final element of the path (the base name), not the entire path.
	// For example, Name would return "hello.go" not "home/gopher/hello.go".
	Name() string

	// IsDir reports whether the entry describes a directory.
	IsDir() bool

	// Type returns the type bits for the entry.
	// The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method.
	Type() FileMode

	// Info returns the FileInfo for the file or subdirectory described by the entry.
	// The returned FileInfo may be from the time of the original directory read
	// or from the time of the call to Info. If the file has been removed or renamed
	// since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist).
	// If the entry denotes a symbolic link, Info reports the information about the link itself,
	// not the link's target.
	Info() (FileInfo, error)
}

Here’s a basic usage example:

package main

import (
	"fmt"
	"log"
	"os"
)

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

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

Check it out on Go play

Maybe you want more information about the file? No problem, let’s access the file info:

package main

import (
	"fmt"
	"log"
	"os"
)

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

	for _, file := range files {
		fileInfo, err := file.Info()
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(file.Name(), file.IsDir(), 
				fileInfo.Size(), fileInfo.ModTime())
	}
}

Check it out on Go play

filepath.Walk

Another option is to use Walk from the filepath package which is part of the standard library.

In this example I’ve also shown the use of Base which returns the last element of path. This should either be a directory or file name.

package main

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

func main() {
	err := filepath.Walk("/tmp/", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			fmt.Println(err)
			return err
		}
		fileName := filepath.Base(path)
		fmt.Println(fileName, info.IsDir())
		return nil
	})
	if err != nil {
		fmt.Println(err)
	}
}

Check it out on Go play

os.File.Readdir

The final example we’ll explore is Readdir which is also part of the os package.

Readdir reads the contents of the directory associated with file and returns a slice of up to n FileInfo values, as would be returned by Lstat, in directory order. Subsequent calls on the same file will yield further FileInfos.

In most cases you’ll probably want to use the ReadDir method though.

package main

import (
	"fmt"
	"os"
)

func main() {
	f, err := os.Open("/tmp/")
	if err != nil {
		fmt.Println(err)
		return
	}
	files, err := f.Readdir(0)
	if err != nil {
		fmt.Println(err)
		return
	}

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

Check it out on Go play

Sorting the results

If you would like the results to be sorted in a particular way I have a few posts on that: