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.
Frequently Asked:
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,
Best Resources to Learn C++:
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