The Boost C++ Libraries

Files and Directories

The member functions presented with boost::filesystem::path simply process strings. They access individual components of a path, append paths to one another, and so on.

In order to work with physical files and directories on the hard drive, several free-standing functions are provided. They expect one or more parameters of type boost::filesystem::path and call operating system functions internally.

Prior to introducing the various functions, it is important to understand what happens in case of an error. All of the functions call operating system functions that may fail. Therefore, Boost.Filesystem provides two variants of the functions that behave differently in case of an error:

boost::system::system_error and boost::system::error_code are presented in Chapter 55. In addition to the inherited interface from boost::system::system_error, boost::filesystem::filesystem_error provides two member functions called path1() and path2(), both of which return an object of type boost::filesystem::path. Since there are functions that expect two parameters of type boost::filesystem::path, these two member functions provide an easy way to retrieve the corresponding paths in case of a failure.

Example 35.10. Using boost::filesystem::status()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\"};
  try
  {
    file_status s = status(p);
    std::cout << std::boolalpha << is_directory(s) << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 35.10 introduces boost::filesystem::status(), which queries the status of a file or directory. This function returns an object of type boost::filesystem::file_status, which can be passed to additional helper functions for evaluation. For example, boost::filesystem::is_directory() returns true if the status for a directory was queried. Besides boost::filesystem::is_directory(), other functions are available, including boost::filesystem::is_regular_file(), boost::filesystem::is_symlink(), and boost::filesystem::exists(), all of which return a value of type bool.

The function boost::filesystem::symlink_status() queries the status of a symbolic link. With boost::filesystem::status() the status of the file referred to by the symbolic link is queried. On Windows, symbolic links are identified by the file extension lnk.

Example 35.11. Using boost::filesystem::file_size()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Windows\\win.ini"};
  boost::system::error_code ec;
  boost::uintmax_t filesize = file_size(p, ec);
  if (!ec)
    std::cout << filesize << '\n';
  else
    std::cout << ec << '\n';
}

A different category of functions makes it possible to query attributes. The function boost::filesystem::file_size() returns the size of a file in bytes. The return value is of type boost::uintmax_t, which is a type definition for unsigned long long. The type is provided by Boost.Integer.

Example 35.11 uses an object of type boost::system::error_code, which needs to be evaluated explicitly to determine whether the call to boost::filesystem::file_size() was successful.

Example 35.12. Using boost::filesystem::last_write_time()
#include <boost/filesystem.hpp>
#include <iostream>
#include <ctime>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Windows\\win.ini"};
  try
  {
    std::time_t t = last_write_time(p);
    std::cout << std::ctime(&t) << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

To determine the time a file was modified last, boost::filesystem::last_write_time() can be used (see Example 35.12).

Example 35.13. Using boost::filesystem::space()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\"};
  try
  {
    space_info s = space(p);
    std::cout << s.capacity << '\n';
    std::cout << s.free << '\n';
    std::cout << s.available << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

boost::filesystem::space() retrieves the total and remaining disk space (see Example 35.13). It returns an object of type boost::filesystem::space_info, which provides three public member variables: capacity, free, and available, all of type boost::uintmax_t. The disk space is in bytes.

While the functions presented so far leave files and directories untouched, there are several functions that can be used to create, rename, or delete files and directories.

Example 35.14. Creating, renaming, and deleting directories
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Test"};
  try
  {
    if (create_directory(p))
    {
      rename(p, "C:\\Test2");
      boost::filesystem::remove("C:\\Test2");
    }
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 35.14 should be self-explanatory. Looking closely, one can see that it’s not always an object of type boost::filesystem::path that is passed to functions, but rather a simple string. This is possible because boost::filesystem::path provides a non-explicit constructor that will convert strings to objects of type boost::filesystem::path. This makes it easy to use Boost.Filesystem since it’s not required to create paths explicitly.

Note

In Example 35.14, boost::filesystem::remove() is explicitly called using its namespace. Otherwise, Visual C++ 2013 would confuse the function with remove() from the header file stdio.h.

Additional functions such as create_symlink() to create symbolic links or copy_file() and copy_directory() to copy files and directories are available as well.

Example 35.15. Using boost::filesystem::absolute()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  try
  {
    std::cout << absolute("photo.jpg") << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 35.15 presents a function that creates an absolute path based on a file name or section of a path. The path displayed depends on which directory the program is started in. For example, if the program was started in C:\, the output would be "C:\photo.jpg".

To retrieve an absolute path relative to a different directory, a second parameter can be passed to boost::filesystem::absolute().

Example 35.16. Creating an absolute path relative to another directory
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  try
  {
    std::cout << absolute("photo.jpg", "D:\\") << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 35.16 displays "D:\photo.jpg".

The last example in this section, Example 35.17, introduces a useful helper function to retrieve the current working directory.

Example 35.17. Using boost::filesystem::current_path()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  try
  {
    std::cout << current_path() << '\n';
    current_path("C:\\");
    std::cout << current_path() << '\n';
  }
  catch (filesystem_error &e)
  {
    std::cerr << e.what() << '\n';
  }
}

Example 35.17 calls boost::filesystem::current_path() multiple times. If the function is called without parameters, the current working directory is returned. If an object of type boost::filesystem::path is passed, the current working directory is set.