In this section, we will implement an app that iterates over a directory and lists the file size of each entry. This is simple for regular files, but if we are looking at a directory entry that itself is a directory, then we have to look into it and summarize the size of all the files it holds.
- First, we need to include all the necessary headers and declare that we use namespace std and filesystem.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <filesystem>
using namespace std;
using namespace filesystem;
- Then we implement a helper function that accepts a directory_entry as an argument and returns its size in the filesystem. If it is not a directory, we simply return the file size calculated by file_size.
static size_t entry_size(const directory_entry &entry)
{
if (!is_directory(entry)) { return file_size(entry); }
- If it is a directory, we need to iterate over all its entries and calculate their size. We end up calling our own entry_size helper function recursively if we stumble upon subdirectories again.
return accumulate(directory_iterator{entry}, {}, 0u,
[](size_t accum, const directory_entry &e) {
return accum + entry_size(e);
});
}
- For better readability, we use the same size_string function as in other recipes in this chapter. It just divides large file sizes in to shorter and nicer ones to read strings with kilo, mega, or giga suffix.
static string size_string(size_t size)
{
stringstream ss;
if (size >= 1000000000) {
ss << (size / 1000000000) << 'G';
} else if (size >= 1000000) {
ss << (size / 1000000) << 'M';
} else if (size >= 1000) {
ss << (size / 1000) << 'K';
} else { ss << size << 'B'; }
return ss.str();
}
- The first thing we need to do in the main function is to check whether the user provided a filesystem path on the command line. If that is not the case, we just take the current folder. Before proceeding, we check whether it exists.
int main(int argc, char *argv[])
{
path dir {argc > 1 ? argv[1] : "."};
if (!exists(dir)) {
cout << "Path " << dir << " does not exist.n";
return 1;
}
- Now, we can iterate over all directory entries and print their sizes and names.
for (const auto &entry : directory_iterator{dir}) {
cout << setw(5) << right
<< size_string(entry_size(entry))
<< " " << entry.path().filename().c_str()
<< 'n';
}
}
- Compiling and running the program yields the following results. I launched it in a folder in the C++ offline reference. As it contains subfolders too, our recursive file size summary helper is immediately helpful.
$ ./file_size ~/Documents/cpp_reference/en/
19M c
12K c.html
147M cpp
17K cpp.html
22K index.html
22K Main_Page.html