page-fault

Filesystem


C++17 introduces standard facilities for dealing with directories, paths, and file permissions. std::filesystem is based on Boost’s filesystem library, but with extensions to support non-POSIX systems.


Core Components

namespace fs = std::filesystem; is implied:


fs::path

Getters

Contains a pathname string which names a file that may or may not exist. Made up of:



There are queries for the following components, which return an empty path if the requested component is not present. There are also has_-prefixed versions which check for the existence of a particular path component:



path also exposes iterators over each of the individual filename components in the path, e.g.

for (const auto& part : fs::path { "C:/Windows/system.ini" })
    std::cout << part << '\n';

Path Operations



Comparison works as expected, for the most part. Shorter paths are ordered before longer paths that are otherwise equivalent. Paths without root directories are ordered before paths with root directories.


Paths have stream operator overloads to read/write to streams while preserving correct (platform-dependent) formatting.


Conversions

To get at the platform-dependent path representation, you can use c_str() or native(). This native format can also be converted to a specific character width (e.g. u8, u16, u32), but this should be used with care on platforms which use wide characters for pathnames (like Windows).


directory_entry

Can be constructed from a path, throwing or updating an error code if construction fails.


Can also be created via a directory_iterator or recursive_directory_iterator. These are input iterators, which visit directory contents in an unspecified order, and may or may not be updated if a file is added/removed after the iterator is constructed.


Both iterator constructors actually return a range with a begin/end, suitable for use with a range-for (or std::begin and std::end can be used to extract real iterators for use with algorithms).

Lots of getters, all fairly self-explanatory.


namespace fs = std::filesystem;

auto sumFileSizes (const fs::path& p)
{
    const auto range = fs::recursive_directory_iterator { p };
    return std::accumulate (begin (range), end (range), 0, [] (auto sum, const auto& entry)
    {
        return sum + (entry.is_regular_file() ? entry.file_size() : 0);
    });
}

Note that calling member functions on the file entry is likely to be faster than calling the non-member functions from the std::filesystem namespace, because the runtime can cache the data appropriately while iterating.


Non-member Utilities

There are some non-member functions that can query properties about a path, without needing to construct a directory_entry. For example, you could call fs::exists (somePath) to check that a particular file exists before using the path to construct a directory_entry.


There are also utilities like absolute and relative for adjusting the path representation, equivalent to check whether two paths refer to the same file, and current_path to get/set the current working directory.


Finally, there are functions to copy files/directories, create new directories and links, delete files/directories, get temporary filepaths, compute free space on a device…


Currently, file modification times use an implementation-defined clock, which makes it difficult to write portable code. In C++20 there should be a portable, properly-specified file_clock.


File permissions can be queried/written by composing/decomposing bitfields using the fs::perms enum. status returns the current file permissions (use operator& to extract specific permission bits) and permissions can replace/add/remove permissions on a specific file. Again, the full suite of POSIX permissions is not available on Windows.


Platform support

Recent clangs/gccs support filesystem, and it should be supported on Windows too, however macOS only supports it in SDK 10.15+, so we can’t start using it there.