warpedvisions.org — Stuff to make you think

HOWTO: Directory recursion in Boost (and other tips)

Boost’s Filesystem library is an incredible library: it abstracts paths, directories, and stat results. It simplifies coding shell problems in C++, it’s portable, and is maintained by a large community of contributors. The one downside of Boost is that some of its newer libraries are poorly documented. ((Something I want to contribute to.)) Until I have time to get involved in the Boost project, I’m going to post examples here.

Traversing a directory tree

This is the coolest feature I’ve found in boost::filesystem so far. It treats directory elements like iterators, and has a convenience iterator that flattens the problem of iterating through a directory tree recursively. The only examples I found for it were in their extensive test sources, ((See convenience tests and operations tests for more examples.)) which are a bit light on comments.

#include "boost/filesystem.hpp"
#include <iostream>

for ( boost::filesystem::recursive_directory_iterator end, dir("./"); 
       dir != end; ++dir ) {
       cout << *dir << std::endl;                                    
}

The example starts in the current working directory, and prints all of the file names (and directories) in inode order. ((Later I’ll try to post an example that uses the stat features to dump extra information.))

Notes:

  1. I don’t alias the namespace here (but I recommend doing so in production code, see below)
  2. Creating an instance of recursive_directory_iterator sets it to the .end() element by default.
  3. The path type supports all standard string paths, including relative paths.

Aliasing Boost namespaces

Here’s how Boost’s own source recommends aliasing their namespaces:

namespace fs = boost::filesystem;
namespace sys = boost::system;

Other cool bits

I’ll write more about these later, but for now here are a few things you’ll find in the library:

  • fs::exists( boost_root / "libs" ), a static function to check if a file exists (-e)
  • fs::current_path() that returns the application’s cwd
  • fs::create_directories( "xx/yy/zz" ) is equivalent to mkdir -p xx/yy/zz
  • fs::is_directory( "xx" ) is the same as Perl/*sh’s -d
  • fs::change_extension("a.txt", ".tex") does the obvious
  • fs::extension("a/b.txt") == "txt" is used to check file extensions
  • fs::remove_all( "x/" ); deletes everything in "x/"
  • ifstream file2( arg_path / "foo" / "bar" ); shows the overloaded / operator!

Things that are great about boost::filesystem‘s approach:

  • Static functions are used for ‘helper’ stuff. Take note C++ devs: this is a great balance for types, it keeps the types noise-free while still providing a great deal of utility.
  • It mirrors Perl/*sh functionality, something most developers should know well.
  • It throws errors (filesystem_error), allowing for some really clean, transactional code.
  • And, it abstracts paths that work on Win32, OSX, Unix, and Linux variants.