1. Сначала включим все необходимые заголовочные файлы и объявим об использовании пространств имен std
и filesystem
:
#include
#include
#include
#include
#include
using namespace std;
using namespace filesystem;
2. Затем реализуем вспомогательную функцию, которая принимает в качестве аргумента directory_entry
и возвращает его размер в файловой системе. Это не каталог, мы просто вернем размер файла, вычисленный с помощью file_size
:
static size_t entry_size(const directory_entry &entry)
{
if (!is_directory(entry)) { return file_size(entry); }
3. Если это каталог, то нужно проитерировать по всем его записям и подсчитать их размер. Мы будем вызывать вспомогательную функцию entry_size
рекурсивно при повторной встрече с подкаталогами:
return accumulate(directory_iterator{entry}, {}, 0u,
[](size_t accum, const directory_entry &e) {
return accum + entry_size(e);
});
}
4. Для повышения читабельности воспользуемся функцией size_string
, которая уже встречалась в этой главе. Она просто сокращает большие размеры файлов, делая их «аккуратнее» и добавляя префиксы «кило», «мега» или «гига»:
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();
}
5. Первое, что нужно сделать в функции main
, — проверить, предоставил ли пользователь путь к файлу в командной строке. Если это не так, то возьмем текущий каталог. Прежде чем продолжить, проверим, существует ли данный каталог:
int main(int argc, char *argv[])
{
path dir {argc > 1 ? argv[1] : "."};
if (!exists(dir)) {
cout << "Path " << dir << " does not exist.\n";
return 1;
}
6. Теперь можно проитерировать по всем записям каталога и вывести на экран их имена и размер:
for (const auto &entry : directory_iterator{dir}) {
cout << setw(5) << right
<< size_string(entry_size(entry))
<< " " << entry.path().filename().c_str()
<< '\n';
}
}
7. Компиляция и запуск программы дадут следующий результат. Я запустил ее для каталога, в котором находится офлайн-справка по С++. Поскольку он содержит и подкаталоги, наша вспомогательная функция, суммирующая размер файла, очень пригодится:
$ ./file_size ~/Documents/cpp_reference/en/
19M c
12K c.html
147M cpp
17K cpp.html 22K index.html
22K Main_Page.html
Как это работает
Вся программа строится на использовании функции file_size
для обычных файлов. Если программа увидит каталог, то рекурсивно спустится в него и вызовет функцию file_size
для всех его записей.
Единственное, что мы сделали для определения того, можем ли вызвать непосредственно file_size
или нужно рекурсивно спуститься дальше, — реализовали предикат is_directory
. Он работает для каталогов, которые содержат только обычные файлы и каталоги.
Поскольку наша программа довольно проста, она даст сбой при следующих условиях.
□ Функция file_size
работает только для обычных файлов и символьных ссылок. Она генерирует исключение во всех других случаях.
□ Несмотря на то что функция file_size
работает для символьных ссылок, она
Чтобы сделать программу из нашего примера более надежной, следует воспользоваться защитным программированием в случаях неверных типов файлов и обработки исключений.
Подбиваем статистику о типах файлов
В предыдущем примере мы реализовали инструмент, который выводит на экран размер всех членов каталога.
В текущем примере тоже будем определять размер рекурсивно, но в этот раз объединим размеры всех файлов с одинаковым
Как это делается