4. Итак, на данном этапе мы вполне уверены: пользователь предоставил filesystem::canonical
возвращает другой объект класса path
. Мы можем вывести на экран его напрямую, но перегруженный оператор <<
класса path
берет в кавычки пути к файлу. Чтобы этого избежать, можем отобразить путь к файлу с помощью методов .c_str()
или .string()
:
cout << canonical(dir).c_str() << '\n';
}
5. Скомпилируем программу и поработаем с ней. Когда мы запустим ее в домашнем каталоге и передадим относительный путь к файлу "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);