C++ : Get the list of all files in a given directory and its sub-directories using Boost & C++17

In this article we will discuss how to fetch the recursive list of all files in a given directory using Boost and C++17 FileSystem Library.

Suppose we have a directory i.e.

/home/user/study/tutorials

and I want list of all files in this directory and its sub directories, but also want to skip certain directory like .svn and log etc.

Let’s see how to do that,

recursive_directory_iterator

Both Boost & c++17 Filesystem Library provides a recursive iterator for the recursive iteration over a directory i.e.

In C++17

std::experimental::filesystem::recursive_directory_iterator

In Boost Filesystem Library,

boost::filesystem::recursive_directory_iterator

It’s an input iterator and using it we can recursively iterate over a directory and all its sub directories.

Create a recursive_directory_iterator object and points to start of directory i.e.

// Create a Recursive Directory Iterator object and points to the starting of directory
filesys::recursive_directory_iterator iter(dirPath);

Create a recursive_directory_iterator object and points to end.

// Create a Recursive Directory Iterator object pointing to end.
filesys::recursive_directory_iterator end;

Now Iterate over all the directories and sub directories by incrementing the iterator till end i.e.

// Iterate till end
while (iter != end)
{
        // .. DO Stuff
	error_code ec;
	// Increment the iterator to point to next entry in recursive iteration
	iter.increment(ec);
	if (ec) {
		std::cerr << "Error While Accessing : " << iter->path().string() << " :: " << ec.message() << '\n';
	}
}

In between, if we dont’t want the iterator over certain sub directories, then we need to call,

no_push() // In Boost Filesystem Library

and

disable_recursion_pending() // In c++17 Fileystsem Library

with iterator pointing to that directory. Calling this function will disable the recursive iteration of current function

Checkout the complete function as follows,

/*
 * Get the list of all files in given directory and its sub directories.
 *
 * Arguments
 * 	dirPath : Path of directory to be traversed
 * 	dirSkipList : List of folder names to be skipped
 *
 * Returns:
 * 	vector containing paths of all the files in given directory and its sub directories
 *
 */
std::vector<std::string> getAllFilesInDir(const std::string &dirPath, 	const std::vector<std::string> dirSkipList = { })
{

	// Create a vector of string
	std::vector<std::string> listOfFiles;
	try {
		// Check if given path exists and points to a directory
		if (filesys::exists(dirPath) && filesys::is_directory(dirPath))
		{
			// Create a Recursive Directory Iterator object and points to the starting of directory
			filesys::recursive_directory_iterator iter(dirPath);

			// Create a Recursive Directory Iterator object pointing to end.
			filesys::recursive_directory_iterator end;

			// Iterate till end
			while (iter != end)
			{
				// Check if current entry is a directory and if exists in skip list
				if (filesys::is_directory(iter->path()) &&
						(std::find(dirSkipList.begin(), dirSkipList.end(), iter->path().filename()) != dirSkipList.end()))
				{
					// Skip the iteration of current directory pointed by iterator
#ifdef USING_BOOST
					// Boost Fileystsem  API to skip current directory iteration
					iter.no_push();
#else
					// c++17 Filesystem API to skip current directory iteration
					iter.disable_recursion_pending();
#endif
				}
				else
				{
					// Add the name in vector
					listOfFiles.push_back(iter->path().string());
				}

				error_code ec;
				// Increment the iterator to point to next entry in recursive iteration
				iter.increment(ec);
				if (ec) {
					std::cerr << "Error While Accessing : " << iter->path().string() << " :: " << ec.message() << '\n';
				}
			}
		}
	}
	catch (std::system_error & e)
	{
		std::cerr << "Exception :: " << e.what();
	}
	return listOfFiles;
}

For Boost FileSystem Library, we need to include following file and create following namespace i.e.

#include <boost/filesystem.hpp>

using namespace boost::system;
namespace filesys = boost::filesystem;
#ifndef USING_BOOST
#define USING_BOOST
#endif

For C++17 FileSystem Library, we need to include following file and create following namespace i.e.

#include <experimental/filesystem>

using namespace std;
namespace filesys = std::experimental::filesystem;

Complete example with Boost header file is as follows,

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <boost/filesystem.hpp>

using namespace boost::system;
namespace filesys = boost::filesystem;
#ifndef USING_BOOST
#define USING_BOOST
#endif

/*
 * Get the list of all files in given directory and its sub directories.
 *
 * Arguments
 * 	dirPath : Path of directory to be traversed
 * 	dirSkipList : List of folder names to be skipped
 *
 * Returns:
 * 	vector containing paths of all the files in given directory and its sub directories
 *
 */
std::vector<std::string> getAllFilesInDir(const std::string &dirPath, 	const std::vector<std::string> dirSkipList = { })
{

	// Create a vector of string
	std::vector<std::string> listOfFiles;
	try {
		// Check if given path exists and points to a directory
		if (filesys::exists(dirPath) && filesys::is_directory(dirPath))
		{
			// Create a Recursive Directory Iterator object and points to the starting of directory
			filesys::recursive_directory_iterator iter(dirPath);

			// Create a Recursive Directory Iterator object pointing to end.
			filesys::recursive_directory_iterator end;

			// Iterate till end
			while (iter != end)
			{
				// Check if current entry is a directory and if exists in skip list
				if (filesys::is_directory(iter->path()) &&
						(std::find(dirSkipList.begin(), dirSkipList.end(), iter->path().filename()) != dirSkipList.end()))
				{
					// Skip the iteration of current directory pointed by iterator
#ifdef USING_BOOST
					// Boost Fileystsem  API to skip current directory iteration
					iter.no_push();
#else
					// c++17 Filesystem API to skip current directory iteration
					iter.disable_recursion_pending();
#endif
				}
				else
				{
					// Add the name in vector
					listOfFiles.push_back(iter->path().string());
				}

				error_code ec;
				// Increment the iterator to point to next entry in recursive iteration
				iter.increment(ec);
				if (ec) {
					std::cerr << "Error While Accessing : " << iter->path().string() << " :: " << ec.message() << '\n';
				}
			}
		}
	}
	catch (std::system_error & e)
	{
		std::cerr << "Exception :: " << e.what();
	}
	return listOfFiles;
}
int main()
{
	std::string dirPath = "/home/user/study";

	// Get recursive list of files in given directory and its sub directories
	std::vector<std::string> listOfFiles = getAllFilesInDir(dirPath);

	// Iterate over the vector and print all files
	for (auto str : listOfFiles)
		std::cout << str << std::endl;

	std::cout << "**********************" << std::endl;

	// Get recursive list of files in given directory and skip given folders
	listOfFiles = getAllFilesInDir(dirPath, { ".svn", "logs" });

	for (auto str : listOfFiles)
		std::cout << str << std::endl;
}

To compile the above example use following command on linux,

g++ -std=c++11 example.cpp -lboost_filesystem -lboost_system

Sample example can be compiled with c++17 file system after replacing header file and namespace as mentioned above. To compile it in c++17, use following command,

g++-7 –std=c++17 example.cpp -lstdc++fs

Leave a Comment

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top