C++ Boost Filesystem Library(Part III): Example Programs
My earlier posts on C++ Boost Libraries introduced the Boost Filesystem Library and discussed some example programs that make use of it. I discuss two more examples in this post. (Be sure to include the needed boost header files as noted in the earlier posts, including creation of the alias to the boost filesystem namespace: namespace bfs = boost::filesystem; )
1. A function to search for a file.
-
// Search for a file with the name 'filename' starting in directory 'dir_path', copy the path of the file in 'pfound' if found, and return true.
-
// Else return false.
-
bool find_file(const bfs::path & dir_path, const std::string & file_name, bfs::path & pfound)
-
{
-
if( !exists(dir_path) || !is_directory(dir_path) )
-
return false;
-
bfs::directory_iterator iter(dir_path), end_iter;
-
for(; iter!= end_iter; ++iter)
-
{
-
if( bfs::is_directory(*iter) )
-
{
-
if( find_file(*iter, file_name, pfound) )
-
return true;
-
}
-
else if( iter->leaf() == file_name )
-
{
-
pfound = *iter;
-
return true;
-
}
-
}
-
return false;
-
}
The function first verifies if the path passed in 'path_dir' exists and if it is a directory. Then it creates a 'directory_iterator' object(introduced in the previous post) by passing this path to its constructor. The loop then iterates over all the contents of the directory, and for every sub-directory found, it calls itself recursively passing this new directory as the starting point. Every file that is found is compared with the file that is to be searched(file_name), and if a match is found, the path is copied into 'pfound' and function returns true. If nothing is found by the end of the loop, 'false' is returned. Remember that as discussed earlier, iter->leaf() returns the last part of a path - the file name. Applying indirection operator to the directory_iterator object returns the file it is pointing to.
2. A simple directory listing (ls/dir) program.
-
void sls(const bfs::path & p)
-
{
-
unsigned long fc=0, dc=0;
-
if( !bfs::exists(p) )
-
std::cout<<"\nFile Not Found:"<<p.native_file_string()<<"\n";
-
-
else if( !bfs::is_directory(p) )
-
std::cout<<"\nFound: " <<p.native_file_string() <<"\n";
-
-
std::cout<<"In directory:"<<p.native_file_string()<<"\n";
-
bfs::directory_iterator iter(p), end_iter;
-
for(; iter != end_iter; ++iter)
-
{
-
try {
-
if(bfs::is_directory(*iter))
-
{
-
++dc;
-
std::cout<<iter->leaf()<<"[Directory]\n";
-
}
-
else
-
{
-
++fc;
-
std::cout<<iter->leaf()<<"\n";
-
}
-
} catch(const std::exception & ex) {
-
std::cout<<iter->leaf() <<": " <<ex.what() <<std::endl;
-
}
-
std::cout<<fc<<" "<<dc<<std::endl;
-
} //for
-
} //sls
The function simply iterates over all the contents of the directory passed to it(p) and prints every file and directory that is found. [Directory] tag is added to the directory names, and at the end of the program the total count of the files and directories is printed. This program only prints the contents of the directory passed, it doesn't traverse its sub-directories. Can you combine the general idea of the above two examples to create a directory listing program that displays the files of all the sub-directories recursively? You can also print more information about the files by using boost filesystem functions like is_symbolic_link(), file_size(), last_write_time() etc[discussed in the earlier posts].
Most of the examples inspired/taken from the Boost website. The website documentation also contains more help on the various formats in which the paths to the files can be represented. The function 'native_file_string()' used in the Example 2 above returns the path in the native format(using '/' as a file separator on Unix platforms and '\' on Windows platforms, for example). To pass the path names as 'path' objects, use the services from fstream.hpp. All Filesystem library related exceptions are available in exception.hpp. The header convenience.hpp contains a few convenience functions(like change_extension()). You can start from the documentation page on the website for further information.

