boost::filesystem


sven-johannsen.de
sven@sven-johannsen.de
c++ user group aachen
07-may-2015

C++ filesystem library

overview

boost::filesystem

platform independed filesystem wrapper

need to know

2 basic concepts:

traditional string based file handling

Example:

int remove( const char * filename );
// error handling with errno
BOOL WINAPI DeleteFile( _In_  LPCTSTR lpFileName );
// error handling with GetLastError

Window is just an other kind of Linux

Note 1: remove is also part of the Posix support on Windows
Note 2: DeleteFileA vs. DeleteFileW
Note 3: Only DeleteFileW is able to delete all files on all windows systems, but different type (wchar_t / const unsigned short*)

portable code (for file handling) (1/3)

It's easy to wrap different functions for simular logic,
but it's hard write portable code for different data types.

portable code (for file handling) (2/3)

Solution: boost::filesystem::path

namespace boost {
  namespace filesystem {
    class path {
    public:
      typedef "see below" value_type;  // char for ISO/IEC 9945, wchar_t for Windows
      typedef std::basic_string<value_type> string_type;
      constexpr value_type preferred_separator;
      ...
    };
}}

portable code (for file handling) (3/3)

Hide the platform depended types in filesystem::path to provide a portable interface.

Example remove:

namespace boost {
  namespace filesystem {
    bool remove(const path& p);
  }
}

boost::filesystem::path p = "C:\\Temp\\bla.txt";
boost::filesystem::remove(p);

path::native

class path
{
    typedef "see below" value_type;  // char for ISO/IEC 9945, wchar_t for Windows
    typedef std::basic_string<value_type> string_type;
    ...
    // native format observers
    const string_type&  native() const noexcept;  // native format, encoding
    const value_type*   c_str() const noexcept;   // native().c_str()

    template <class String>
    String string(const codecvt_type& cvt=codecvt()) const;                // native format

    const string        string(const codecvt_type& cvt=codecvt()) const;   // native format
    const wstring       wstring(const codecvt_type& cvt=codecvt()) const;  // ditto
    // u16string(), u32string()
    ...
};

using path::native

  using namespace boost::filesystem;

  path p = "myfolder/myfile.txt";
  std::string name1 = p.string();   // "myfolder/myfile.txt";
  std::wstring name2 = p.wstring(); // L"myfolder/myfile.txt";

  auto name3 = p.native();
  std::cout << typeid(name3).name() << std::endl;
  // class std::basic_string<wchar_t,struct std::char_traits<wchar_t>,class std::allocator<wchar_t> >

#ifdef _WIN32
 assert(typeid(name3) == typeid(std::wstring));
#else
 assert(typeid(name3) == typeid(std::string));
#endif

path::generic_string

class path
{
    ...
    // generic format observers
    template <class String>
    String generic_string() const;

    const string        generic_string(const codecvt_type& cvt=codecvt()) const;   // generic format
    // generic_wstring, generic_u16string(), generic_u32string()
    ...
};

using path::generic_string

  using namespace boost::filesystem;

  path p = "myfolder\\myfile.txt";
  std::string native_name = p.string();
  std::string generic_name = p.generic_string();

  std::cout << "native_name:  " << native_name  << std::endl;
  // native_name:  myfolder\myfile.txt
  std::cout << "generic_name: " << generic_name << std::endl;
  // generic_name: myfolder/myfile.txt
  std::cout << "pref. sep: " << (char)path::preferred_separator << std::endl;
  // pref. sep: \

string wrapper

The class path is wrapper for a string with filesystem reletated convenience functions like:

string wrapper

using namespace boost::filesystem;
using namespace std;

path p = "r:\\develop\\git\\texte\\filesystem\\source\\path_test2.cpp";

string parent =   p.parent_path().string(); // r:\develop\git\texte\filesystem\source
string filename = p.filename().string();    // path_test2.cpp
string stem =     p.stem().string();        // path_test2
string ext =      p.extension().string();   // .cpp
bool bAbsolute =  p.is_absolute();          // true
bool bHasRoot =   p.has_root_directory();   // true

nameing

filesystemmy companyexample
pathfull_pathC:\temp\filename.txt
parent_pathpathC:\temp
filenamefull_filenamefilename.txt
stemfilennamefilename
extensionextension.txt

error handling

Exception plus error_code:

a set of 2 functions to support 2 different error handling concepts

// throw boost::filesystem_error
bool remove(const path& p);

// set the error code
bool remove(const path& p, system::error_code& ec);

error handling

Exceptions

using namespace boost::filesystem;
using namespace std;

try {
  path self(argv[0]);
  remove(self);  // should fail: program is in use
}
catch (const boost::filesystem::filesystem_error& ex) {
  // std::exception is also OK
  cout << ex.what() << endl;
  // boost::filesystem::remove: Access is denied: "D:\build\filesystem\Debug\error_handling1.exe"
}

error handling

system::error_code

using namespace boost::filesystem;
using namespace std;

boost::system::error_code ec;
path self(argv[0]);
remove(self, ec);  // should fail: program is in use
if (ec) {
  cout << ec.message() << endl;
  // Access is denied
}

using boost::filesystem

directory_iterator

Iterate over all directory entries

(no pattern matting!)

namespace fs = boost::filesystem;

for (fs::directory_iterator it(p);
     it != fs::directory_iterator(); ++it) {
  // pattern matching missing...

  if(fs::is_directory(*it))
    cout << "[" << it->path().filename().string() << "]" << endl;
  else if(fs::is_regular_file(*it))
    cout << it->path().filename().string() << endl;
  else
    cout << "error: " << it->path().string() << endl;
  }
}

recursive_directory_iterator

Iterate recursive over all directory entries

if (fs::is_directory(p)) {
  for (fs::recursive_directory_iterator it(p), itEnd;
       it != itEnd; ++it) {
    cout << it->path().filename().string() << " " << endl;
  } 
} else {
    cout << p.filename() << endl;
}

(recursive_) directory_iterator with error handlering

with error handling for increment

boost::system::error_code ec;

if (fs::is_directory(p)) {
  for (fs::recursive_directory_iterator it(p), itEnd; 
       it != itEnd; it.increment(ec)) {
    if(ec)
      cout << "Error: " << ec.message() << " for " << p << endl;
    else
      cout << it->path().filename().string() << " " << endl;
  } 
} else {
    cout << p.filename() << endl;
}

commands

example: mkdir

namespace fs = boost::filesystem;

fs::path target(argv[1]);

if (!fs::exists(target)) {
  fs::create_directory(target);
} else if (!is_directory(target)) {
  cerr << "Error to create: " << target << endl;
}

example: pwd

namespace fs = boost::filesystem;

fs::path p = fs::current_path();
std::cout << p.string() << std::endl;

copy & create

functions description
copy call copy_directory, copy_file or copy_symlink
copy_directory copy folder without content
copy_file copy single file
copy_symlink copy symbolic link
create_directories mulit level
create_directory single level
create_hard_link if supported by file system
create_symlink if supported by file system

path operations 1

functions description
absolute make a relative path absolute (based on current path)
canonical eliminate all .. and symbolic links
current_path pwd
initial_path the current_path on program start (at the time of the first call of initial_path )
temp_directory_path temp. folder
unique_path a unique path based on a pattern
system_complete resolve a path to a program / shared library / dll

path operations 2

functions description
exists file or folder exists
rename rename file, folder or symbolic link
remove delete file, folder or symbolic link
remove_all delete recursive
permissions check the permission of a file, folder or symbolic link
space free space on a device
status regular file, directory, socket, fifo, ...
status_known check for a specific status

file operations

functions description
file_size file size
resize_file resize a file
last_write_time V3: std::time_t, n3940: std::chrono...
hard_link_count .
read_symlink .
symlink_status .

tests

simple tests for path objects:

functions description
is_directory folder
is_regular_file file
is_symlink simbolic link
is_other no directory, no file, no symlink
is_empty empty file

file streams

C++98/03
std::ofstream(const char* filename); 
C++11
std::ofstream(const string& filename); 
boost::filesystem
boost::filesystem::ofstream(const boost::filesystem::path& path); 

file streams example

example: cat

namespace fs = boost::filesystem;

fs::path p = "C:\\temp\\a.txt";

fs::ifstream ifs(p);
if (ifs) {
  for (std::istreambuf_iterator<char> it(ifs); 
       it != std::istreambuf_iterator<char>(); ++it) {
    cout << *it;
  }
}
cout << endl;

-

goto cmake_presentation;

/