📚 Hub Books: Онлайн-чтение книгРазная литератураC++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+
1 ... 111 112 113 114 115 116 117 118 119 ... 121
Перейти на страницу:
<< path{"testdir"} / "foobar.txt" << 'n';

5. Рассмотрим работу с функцией canonical и составными путями. Передавая функции canonical относительный путь к файлу, например "foobar.txt", и составной абсолютный путь current_path()/"testdir", получаем существующий абсолютный путь к файлу. В следующем обращении к функции передаем наш путь p (т.е. "testdir/foobar.txt") и абсолютный путь current_path(), который направляет нас в каталог "testdir" и обратно. Это то же самое, что и current_path(), из-за косвенных адресов. В обоих вызовах функция canonical должна возвратить одинаковый абсолютный путь.

cout << "canonical testdir : "

     << canonical("foobar.txt",

                   current_path()/"testdir")

     << "ncanonical testdir 2 : "

     << canonical(p, current_path()/"testdir/..")

     << 'n';

6. Кроме того, можно проверить эквивалентность двух путей, не являющихся каноническими. Функция equivalence приводит к каноническому виду пути к файлам, которые она принимает в качестве аргументов, и в конечном итоге возвращает значение true при условии, что они описывают один и тот же путь. Для этой проверки путь к файлу должен действительно существовать, в противном случае функция сгенерирует исключение.

  cout << "equivalence: "

       << equivalent("testdir/foobar.txt",

                     "testdir/../testdir/foobar.txt")

       << 'n';

}

7. Компиляция и запуск программы дадут следующий результат. Функция current_path() возвращается к домашнему каталогу на моем ноутбуке, поскольку я запустил приложение оттуда. К нашему относительному пути p был добавлен префикс, состоящий из данной папки, с помощью функций absolute_path, system_complete и canonical. Мы видим, что функции absolute_path и system_complete выдают абсолютно одинаковое описание пути файла в моей системе, потому что это Mac (на Linux будет так же). В компьютере с операционной системой Windows функция system_complete добавит префикс "C:" или любого другого диска, в котором расположен рабочий каталог.

$ ./canonical_filepath

current_path    : "/Users/tfc"

absolute_path   : "/Users/tfc/testdir/foobar.txt"

system_complete : "/Users/tfc/testdir/foobar.txt"

canonical(p)    : "/Users/tfc/testdir/foobar.txt"

"testdir/foobar.txt"

canonical testdir   : "/Users/tfc/testdir/foobar.txt"

canonical testdir 2 : "/Users/tfc/testdir/foobar.txt"

equivalence: 1

8. Мы не обрабатываем никаких исключений в нашей короткой программе. При удалении файла foobar.txt из каталога testdir программа прекращает свою работу из-за исключения. Функция canonical требует наличия действительного пути файла. Существует также функция weakly_canonical, которая не предъявляет подобных требований.

$ ./canonial_filepath

current_path : "/Users/tfc"

absolute_path : "/Users/tfc/testdir/foobar.txt"

system_complete : "/Users/tfc/testdir/foobar.txt"

terminate called after throwing an instance of

'std::filesystem::v1:: cxx11::filesystem_error'

what(): filesystem error: cannot canonicalize:

No such file or directory [testdir/foobar.txt] [/Users/tfc]

Как это работает

Цель данного примера заключается в том, чтобы увидеть, как легко создавать новые пути динамически. В основном это связано с наличием в классе path удобного перегруженного оператора /. Кроме того, функции файловой системы хорошо работают с абсолютными и относительными путями к файлам, а также с путями, которые содержат косвенные адреса . и ...

Есть довольно много функций, которые возвращают части экземпляра path, иногда даже преобразуя их. Не будем перечислять все существующие функции, поскольку для знакомства с ними лучше всего обратиться к справочным материалам по C++.

Однако функции-члены класса path, возможно, стоит рассмотреть поближе. Посмотрим, каким функциям-членам класса path соответствуют конкретные части пути к файлу. На следующей диаграмме показано, что пути файлов в Windows несколько отличаются от путей файлов в UNIX/Linux (рис. 10.1).

Как видите, функции-члены класса path возвращаются для абсолютного пути. Для относительных путей root_path, root_name и root_directory пусты. relative_ path, соответственно, возвращает путь, только если тот уже является относительным. 

Составляем список всех файлов в каталоге

Конечно же, каждая операционная система, предлагающая поддержку файловой системы, также поставляется с утилитой, которая просто перечисляет все файлы внутри каталога в файловой системе. Самые простые примеры — команда ls в Linux, MacOS и других UNIX-подобных операционных системах. В DOS и Windows существует команда dir. Обе команды составляют список из всех файлов в каталоге и предоставляют дополнительную информацию, такую как размер файла, разрешения и т.д.

Однако переопределение такого инструмента также является хорошим примером, который позволит нам научиться выполнять обходы каталогов и файлов. Давайте просто сделаем это!

Наша собственная утилита ls/dir будет способна упорядочивать по имени все файлы в каталоге, их флаги разрешения доступа и отображать количество байт, которые они занимают в файловой системе.

Как это делается

В этом примере мы реализуем небольшой инструмент, который составляет список файлов в любом предоставленном пользователем каталоге. Он будет упорядочивать файлы в списке не только по имени, но и по типу, размеру и разрешениям доступа.

1. Сначала включим необходимые заголовочные файлы и объявим об использовании пространств имен std и filesystem по умолчанию:

#include <iostream>

#include <sstream>

#include <iomanip>

#include <numeric>

#include <algorithm>

#include <vector>

#include <filesystem>

using namespace std;

using namespace filesystem;

2. Понадобится вспомогательная функция file_info. Она принимает ссылку на объект directory_entry и извлекает из нее путь, а также объект file_status (с помощью функции status), который содержит тип файла и информацию о правах. Наконец, она извлекает и размер записи, если это обычный файл. Для каталогов и особых файлов мы просто возвращаем значение 0. Вся информация упаковывается в кортеж.

static tuple<path, file_status, size_t>

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'; }

 

1 ... 111 112 113 114 115 116 117 118 119 ... 121
Перейти на страницу:

Комментарии

Обратите внимание, что комментарий должен быть не короче 20 символов. Покажите уважение к себе и другим пользователям!

Никто еще не прокомментировал. Хотите быть первым, кто выскажется?