chitay-knigi.com » Разная литература » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 110 111 112 113 114 115 116 117 118 ... 121
Перейти на страницу:
файлу "src", она выведет на экран полный абсолютный путь к файлу.

$ ./normalizer src

/Users/tfc/src

6. Когда мы снова запускаем программу в домашнем каталоге, но даем ей запутанное относительное описание пути к файлу, в котором сначала прописывается вход в папку Desktop, потом прописывается выход из нее с помощью косвенного адреса .., затем входим в папку Documents и выходим из нее, чтобы в конечном итоге попасть в каталог src, программа отображает тот же путь файла, что и ранее!

$ ./normalizer Desktop/../Documents/../src

/Users/tfc/src

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

Этот начальный пример работы с std::filesystem мы сделали относительно коротким и прямолинейным. Мы инициализировали объект класса path на основе строки, которая содержит описание пути к файлу. Класс std::filesystem::path имеет самое первостепенное значение в тех ситуациях, когда мы используем библиотеку, связанную с файловой системой, поскольку с ним связано большинство функций и классов.

Функция filesystem::exists позволяет проверить, существует ли указанный путь файла на самом деле. До сего момента мы не можем быть в этом уверены, поскольку возможно создавать объекты класса path, которые не относятся к реальному объекту файловой системы. Функция exists всего лишь принимает экземпляр класса path и возвращает значение true в том случае, если он действительно существует. Эта функция способна сама определить, какой путь мы ей передали (абсолютный или относительный), что делает ее очень комфортной в применении.

Наконец, мы использовали функцию filesystem::canonical для каталога, чтобы вывести на экран его нормализованную форму:

path canonical(const path& p, const path& base = current_path());

Функция canonical принимает путь к файлу и в качестве необязательного второго аргумента еще один путь к файлу. Второй путь base добавляется к пути файла p в том случае, если p является относительным. После этого функция canonical пытается убрать все косвенные адреса . и .. .

Для вывода результата на экран мы использовали метод .c_str(), которому передали канонический путь к файлу. Мы сделали так потому, что перегруженный оператор << для выходных потоков берет пути к файлам в кавычки, а это не всегда желательно.

Дополнительная информация

Функция canonical генерирует исключение типа fileystem_error, если путь, который мы хотим привести к каноническому виду, не существует. Для предотвращения этого мы проверили наш путь к файлу с помощью функции exists. Но было ли достаточно данной проверки, чтобы необработанные исключения не генерировались? Нет.

Обе функции, как exists, так и canonical, способны генерировать исключения типа bad_alloc. Если бы эти исключения сгенерировались, кто-то мог бы утверждать, что программа все равно обречена. Более важная, а также гораздо более вероятная проблема возникает, когда где-то между проверкой существования файла и процессом приведения его к каноническому виду некто переименовывает или удаляет основной файл! В этом случае функция canonical сгенерирует сообщение об ошибке filesystem_error, хотя мы ранее уже убедились в том, что файл существует.

Большая часть функций файловой системы имеет еще одну перегруженную версию, которая принимает те же аргументы, а также ссылку на std::error_code:

path canonical(const path& p, const path& base = current_path());

path canonical(const path& p, error_code& ec);

path canonical(const std::filesystem::path& p,

               const std::filesystem::path& base,

               std::error_code& ec);

Таким образом, можно выбрать, окружать ли запросы к функциям файловой системы конструктами try-catch, или же проверять наличие ошибок вручную. Обратите внимание: это изменяет только поведение ошибок, связанных с файловой системой! Если в системе заканчивается память, то возможна генерация более сложных исключений, таких как bad_alloc, которые могут иметь или не иметь параметр ec. 

Получаем канонические пути к файлам из относительных путей

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

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

Мы увидим, как обращаться с путями и их композицией/декомпозицией, на примере работы с абсолютными и относительными путями.

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

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

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

#include <iostream>

#include <filesystem>

using namespace std;

using namespace filesystem;

2. Затем объявляем пример пути к файлу. На данный момент неважно, существует ли текстовый файл, на который он ссылается. Тем не менее есть функции, генерирующие исключения, если требуемого файла нет.

int main()

{

  path p {"testdir/foobar.txt"};

3. Сейчас мы познакомимся с четырьмя разными функциями библиотеки для работы с файловой системой. Функция current_path возвращает путь, в котором в данный момент выполняется программа, — так называемый рабочий каталог. Функция absolute принимает относительный путь к файлу наподобие нашего пути p и возвращает абсолютный, однозначный путь во всей файловой системе.

Функция system_complete делает практически то же самое, что и функция absolute в Linux, MacOS или других UNIX-подобных операционных системах. В Windows мы получим абсолютный путь к файлу, только вначале будет добавлено буквенное обозначение тома диска (например, "C:"). Функция canonical опять же делает то же самое, что и функция absolute, но потом дополнительно убирает все косвенные адреса, такие как "." (сокращение для «текущий каталог») или ".." (сокращение для «один каталог вверх»). Мы рассмотрим работу с данными косвенными адресами в следующих шагах.

cout << "current_path      : " << current_path()

     << "nabsolute_path   : " << absolute(p)

     << "nsystem_complete : " << system_complete(p)

     << "ncanonical(p)    : " << canonical(p)

     << 'n';

4. Еще одна приятная особенность класса path заключается в том, что он перегружает оператор /. Таким образом, можно сцеплять имена папок и имена файлов с помощью данного оператора и составлять из них пути файлов. Попробуем это и отобразим составной путь:

cout

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

Комментарии
Минимальная длина комментария - 25 символов.
Комментариев еще нет. Будьте первым.