How to list all files in a directory recursively using Golang?

This post will look at how we can list all the files in a directory using Golang. We will approach the solution from two perspectives.

We will work on the below project structure –

TestDir
   |_ _ _ file1.txt
   |_ _ _ file2.txt
   |_ _ _ dir1
             |_ _ _ file3.txt
             |_ _ _ dir2
                       |_ _ _ file5.txt
                       |_ _ _ file6.txt
                       |_ _ _ dir3
List the immediate next-level files and directories

We will list all the file and directory names inside the TestDir folder. So, our code should print “file1.txt”, “file2.txt”, and “dir1”.

The “io/ioutil” package in Golang provides a ReadDir() function that lets us read the directory contents. We can pass the directory path in the ReadDir() function argument, and it will return us the slice of values along with any error that it encounters.

Syntax of using ReadDir() function
files, err := ioutil.ReadDir("E:\\TestDir")

After getting a slice of FileInfo, we can iterate over them one by one using a for…range loop in Golang. And we can get the name of each file using the Name() function.

package main

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

func main() {

	files, err := ioutil.ReadDir("E:\\TestDir")

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

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

}

Output –

dir1
file1.txt
file2.txt

We can see that the program printed the list of files or directories inside the TestDir directory.

If any error comes while reading through the directory’s contents, it will be stored in the err variable. We will use log.Fatal(err) if any error is encountered. Fatal is equivalent to Print() followed by a call to os.Exit(1).

What if we only want to list the files and not the directories using Golang?

This can be achieved using another function, “IsDir()”.

IsDir() will return true if the file is a directory; otherwise false.

  • We will modify the code within the for loop to check whether the file being iterated is a directory.
  • And we will print the file name only if IsDir() returns false.
package main

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

func main() {

	files, err := ioutil.ReadDir("E:\\TestDir")

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

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

}

Output –

file1.txt
file2.txt
Listing all files in nested directories

Here, we will use recursion to go into the subdirectories and then keep iterating until no directories are left to iterate.

We will use the below steps to list all files in a directory, including those present in subdirectories.

  1. Make a function listFiles() that accepts a directory path as a parameter.
  2. Iterate over the contents of the directory that is passed into the arguments.
  3. If we encounter a file, print its name.
  4. If we encounter a directory, then pass the path of this subdirectory to the listFiles() function and repeat steps 1 to 3. We will use IsDir() method to check whether the currently iterated element is a directory or not.
  5. Repeat steps 1 to 4 until no file or directory is left to iterate.

Below is our listFiles() function

func listFiles(path string) {

	//Reading contents of the directory
	files, err := ioutil.ReadDir(path)

	// error handling
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if file.IsDir() {
			subDirectoryPath := filepath.Join(path, file.Name()) // path of the subdirectory
			listFiles(subDirectoryPath)                          // calling listFiles() again for subdirectory
		} else {
			fmt.Println(file.Name()) // printing the file name
		}
	}
}

Remember, we are still using the file structure we mentioned at the start of this post.

Now, let’s write the whole program.

package main

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

func listFiles(path string) {

	//Reading contents of the directory
	files, err := ioutil.ReadDir(path)

	// error handling
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if file.IsDir() {
			subDirectoryPath := filepath.Join(path, file.Name()) // path of the subdirectory
			listFiles(subDirectoryPath)                          // calling listFiles() again for subdirectory
		} else {
			fmt.Println(file.Name()) // printing the file name
		}
	}
}

func main() {

	listFiles("E:\\TestDir")
}

Output –

file5.txt
file6.txt
file3.txt
file1.txt
file2.txt

So, here we have a list of all our files in a directory and its subdirectories.

We can also print the names of subdirectories.

func listFiles(path string) {

	//Reading contents of the directory
	files, err := ioutil.ReadDir(path)

	// error handling
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if file.IsDir() {
			fmt.Println(file.Name())                             // printing the directoty name
			subDirectoryPath := filepath.Join(path, file.Name()) // path of the subdirectory
			listFiles(subDirectoryPath)                          // calling listFiles() again for subdirectory
		} else {
			fmt.Println(file.Name()) // printing the file name
		}
	}
}

This will also list the directory names along with the file names.

We hope that you have liked the article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at [email protected].

Liked the article? Share this on

Leave a Comment

Your email address will not be published. Required fields are marked *