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.
Frequently Asked:
- C++: How to get filename from a path with or without extension | Boost | C++17 FileSytem Library
- C++ : Get the list of all files in a given directory and its sub-directories using Boost & C++17
- C++ : Check if given path is a file or directory using Boost & C++17 FileSystem Library
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