В этом примере мы реализуем небольшой инструмент, который составляет список файлов в любом предоставленном пользователем каталоге. Он будет упорядочивать файлы в списке не только по имени, но и по типу, размеру и разрешениям доступа.
1. Сначала включим необходимые заголовочные файлы и объявим об использовании пространств имен std
и filesystem
по умолчанию:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace filesystem;
2. Понадобится вспомогательная функция file_info
. Она принимает ссылку на объект directory_entry
и извлекает из нее путь, а также объект file_status
(с помощью функции status
), который содержит тип файла и информацию о правах. Наконец, она извлекает и размер записи, если это обычный файл. Для каталогов и особых файлов мы просто возвращаем значение 0
. Вся информация упаковывается в кортеж.
static tuple
file_info(const directory_entry &entry)
{
const auto fs (status(entry));
return {entry.path(),
fs,
is_regular_file(fs) ? file_size(entry.path()) : 0u};
}
3. Кроме того, понадобится вспомогательная функция type_char
. Путь может представлять не только каталоги и простые текстовые/бинарные файлы. Операционные системы предоставляют множество разнообразных типов, которые абстрагируют что-то еще, например интерфейсы аппаратных устройств в виде так называемых символьных/блочных файлов. В библиотеке для работы с файловой системой, расположенной в STL, есть множество функций-предикатов для них. Таким образом, можно вернуть букву 'd'
для каталогов, букву 'f'
для обычных файлов и т.д.:
static char type_char(file_status fs)
{
if (is_directory(fs)) { return 'd'; }
else if (is_symlink(fs)) { return 'l'; }
else if (is_character_file(fs)) { return 'c'; }
else if (is_block_file(fs)) { return 'b'; }
else if (is_fifo(fs)) { return 'p'; }
else if (is_socket(fs)) { return 's'; }
else if (is_other(fs)) { return 'o'; }
else if (is_regular_file(fs)) { return 'f'; }
return '?';
}
4. Напишем еще одну вспомогательную функцию, rwx
. Она принимает переменную perms
(просто возвращающую тип класса перечисления из библиотеки для работы с файловой системой) и возвращает строку наподобие "rwxrwxrwx"
, которая описывает настройки прав для файла. Первая группа символов "rwx"
описывает права на чтение, запись и исполнение (read, write and execution) для владельца файла. Следующая группа описывает те же права для всех пользователей, являющихся частью "rwxrwxrwx"
означает, что все пользователи могут получить доступ к объекту любым способом; строка "rw-r--r--"
— что только владелец файла может читать и изменять его, а все остальные — только читать. Мы просто создадим строку на основе этих значений бит за битом. Лямбда-выражение поможет выполнить повторяющуюся работу, связанную с проверкой, содержит ли переменная p
типа perms
конкретный бит владельца, и возвратит символ '-'
или соответствующую букву:
static string rwx(perms p)
{
auto check ([p](perms bit, char c) {
return (p & bit) == perms::none ? '-' : c;
});
return {check(perms::owner_read, 'r'),
check(perms::owner_write, 'w'),
check(perms::owner_exec, 'x'),
check(perms::group_read, 'r'),
check(perms::group_write, 'w'),
check(perms::group_exec, 'x'),
check(perms::others_read, 'r'),
check(perms::others_write, 'w'),
check(perms::others_exec, 'x')};
}
5. Наконец, последняя вспомогательная функция принимает целочисленный размер файла и преобразует его в читабельный вид. Мы просто проигнорируем точку при делении чисел и округлим их до ближайшего значения кило-, мега- или гигабайт.
static string size_string(size_t size)
{
stringstream ss;