How to list the files in a directory with Go

The Go standard library provides several packages for working with files and directories. This article examines some of the ways you can fetch a list of all the files in a directory using stdlib methods.

Let’s consider four ways to retrieve a list of files in a directory with Go. They’re all different in subtle ways so the method you’ll end up choosing will ultimately depend on what you’re trying to achieve.

Using ioutil.ReadDir

The ioutil.ReadDir method takes a directory name as its only argument, and returns a slice of directory entries sorted by name. The resulting slice contains os.FileInfo types, which provide the methods listed here. You can loop over the returned slice to access each individual entry.

Here’s an example that lists all the files in the current directory:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

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

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

VSCode screenshot

Using filepath.Walk

The above method of accessing files is great if you do not need to scan sub-directories. Otherwise, it may not meet your needs and that’s when the filepath.Walk method may come in handy.

It accepts a root directory name and a WalkFunc function type with the signature shown below. This function is called for each file or directory in the tree, including the root.

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

Here’s how to use filepath.Walk to print out all the files in a directory including all sub-directories:

package main

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

func main() {
	err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		fmt.Println(path)
		return nil
	})

	if err != nil {
		log.Println(err)
	}
}

As you can see from the screenshot below, the contents of the counter directory is printed unlike when we employed ioutil.ReadDir above.

VSCode screenshot

It is important to note that filepath.Walk will not follow symbolic links and can be inefficient for really large directories.

Using os.File.Readdir

The ioutil.ReadDir method actually uses the Readdir method of os.File to scan the directory, and then sorts the slice afterwards by name. If you don’t need the results to be sorted, you can speed things up a bit by using the os.File.Readdir method directly as shown below:

package main

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

func main() {
	file, err := os.Open(".")
	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	list, err := file.Readdir(-1)
	if err != nil {
		log.Fatal(err)
	}

	for _, f := range list {
		fmt.Println(f.Name())
	}
}

VSCode screenshot

Using os.File.Readdirnames

If all you need is the names of the files without all the extra information that the above methods provide, you can use os.File.Readdirnames which takes an integer (n) and reads at most n names.

If n is zero or less, all the names in the directory will be returned in a single slice. Here’s an example:

package main

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

func main() {
	file, err := os.Open(".")
	if err != nil {
		log.Fatal(err)
	}

	defer file.Close()

	names, err := file.Readdirnames(0)
	if err != nil {
		log.Fatal(err)
	}

	for _, v := range names {
		fmt.Println(v)
	}
}

VSCode screenshot

Wrap up

As you can see, listing files in a directory is a trivial task in Go and can be done in many ways. If you know of another method that is not covered above, please share it in the comments.

Thanks for reading, and happy coding!