CS253: Software Development with C++

Spring 2021

Filesystem

Show Lecture.Filesystem as a slide show.

CS253 Filesystem

Major filesystem classes

#include <filesystem> introduces a lot of new symbols, quarantined to their own namespace std::filesystem to avoid conflicts, so put using namespace std::filesystem; in your code.

<filesystem> defines several classes, including:

path

path p("/usr/bin/cat");
cout << "path:        " << p               << '\n'
     << "native:      " << p.native()      << '\n'
     << "parent_path: " << p.parent_path() << '\n'
     << "filename:    " << p.filename()    << '\n'
     << "stem:        " << p.stem()        << '\n'
     << "extension:   " << p.extension()   << '\n';
path:        "/usr/bin/cat"
native:      /usr/bin/cat
parent_path: "/usr/bin"
filename:    "cat"
stem:        "cat"
extension:   ""

filesystem_error

Many filesystem functions take an optional error_code argument. If that argument isn’t given, then the function throws a filesystem_error object if things go bad, which has a nice error message.

try {
    cout << "/etc/group: " << file_size("/etc/group") << endl;
    cout << "doh!: " << file_size("doh!") << endl;
}
catch (const filesystem_error &oops) {
    cerr << oops.what() << '\n';
}
/etc/group: 1535
doh!: filesystem error: cannot get file size: No such file or directory [doh!]

error_code

If the optional error_code argument is given, nothing is thrown:

for (auto fn : {"/bin/cc", "/bin/cat"}) {
    error_code ec;
    string s = read_symlink(fn, ec);
    if (ec)
        cerr << fn << ": " << ec.message() << '\n';
    else
        cout << fn << " -> " << s << '\n';
}
/bin/cc -> gcc
/bin/cat: Invalid argument

An error_code in a boolean context is true iff the last operation was bad.

Iteration

path home(getenv("HOME"));
path pub(home / "pub");
for (directory_entry d : directory_iterator(pub))
    if (d.path().extension() == ".txt")
        cout << d.path().filename() << '\n';
"abcdefg.txt"
"hamlet.txt"
"common-words.txt"

Recursive Iteration

path home(getenv("HOME"));
path pub(home / "pub");
for (auto &d : recursive_directory_iterator(pub))
    if (d.path().stem() == "README")
        cout << d << '\n';
"/s/bach/a/class/cs253/pub/Example/README.txt"

A path is printed with "quotes" so we can read & write paths containing whitespace.

file_status

$ ls -lhog /etc/group
-rw-r--r-- 1 1.5K Nov 30  2022 /etc/group

status() returns a file_status object:

file_status s = status("/etc/group");
file_type t = s.type();
perms p = s.permissions();
if ((p & perms::owner_read) != perms::none)
    cout << "readable by owner\n";
if (t == file_type::regular)
    cout << "a regular file\n";
readable by owner
a regular file

path and fstream

const path home(getenv("HOME"));
auto fname(home / "pub/dwarfs");
if (ifstream in(fname); in.good())
    for (string s; getline(in, s); )
        cout << s << '\n';
else
    cerr << "can’t open " << fname << " for reading.\n";
Bashful
Doc
Dopey
Grumpy
Happy
Sleepy
Sneezy

And …

absolute()composes an absolute pathremove()removes a file or empty directory
canonical()/weakly_canonical()composes a canonical pathremove_all()removes file/directory & contents, recursively
relative()/proximate()composes a relative pathrename()moves or renames a file or directory
copy()copies files or directoriesresize_file()truncate or zero-fill
copy_file()copies file contentsspace()determines available free space
copy_symlink()copies a symbolic linkstatus()determines file attributes
create_directory()/create_directories()creates new directorysymlink_status()determines symlink target attributes
create_hard_link()creates a hard linktemp_directory_path()directory for temporary files
create_symlink()/create_directory_symlink()creates a symlinkis_block_file()is this a block device?
current_path()returns/sets the current directoryis_character_file()is this a a character device?
exists()does this path exist?is_directory()is this a a directory?
equivalent()do two paths refer to the same file?is_empty()is this a an empty file or directory?
file_size()returns the size of a fileis_fifo()is this a a named pipe?
hard_link_count()returns the number of hard linksis_other()is this a other file?
last_write_time()gets/sets time of the last data changeis_regular_file()is this a regular file?
permissions()modifies file access permissionsis_socket()is this a named IPC socket?
read_symlink()obtains the target of a symbolic linkis_symlink()is this a symbolic link?