Зачем использовать POSIX в качестве основы для представления файловых путей?
POSIX является основой для многих строковых форматов представления файловых путей, включая часть URL в URI и родной формат Windows. Он прост и знаком многим разработчикам. На многих системах очень легко реализовать поддержку этого формата, потому что этот формат либо является родным для них (Unix и Windows), либо предоставляемую операционной системой библиотеку поддержки POSIX (z/OS, OS/390, многие другие).
Почему бы не использовать полный URI (Universal Resource Identifier) для представления файловых путей?
URI мог обеспечить гораздо более широкие возможности, чем дает библиотека Boost.Filesystem, так как область применения URI простирается гораздо дальше, чем просто файлы и директории в большинстве операционных систем. Потому с точки зрения исходной цели создания библиотеки Boost.Filesystem - "портабельные операции над файлами", полные возможности URI кажутся чрезмерными.
Почему бы не сделать path базовым классом для производных от него классов directory_path и file_path?
А зачем суетиться? Поведение всех этих трех классов практически идентично. Несколько ранних версий требовали от пользователя идентифицировать каждый путь как путь к файлу или к каталогу, но это, кажется, лишь увеличило количество ошибок и усложнило читабельность кода, а выгод такое разделение не дает.
Почему полностью специфицированные пути называются complete (законченными), а не absolute - абсолютными?
Чтобы избежать укоренившихся заблуждений программистов (что вы имеете в виду, неужели "/foo" не является абсолютным на каких-либо системах?), привыкших к файловым системам с единым корнем. Использование непривычного имени для концепции и соответствующих функций понуждает программиста читать документацию, вместо того, чтобы делать предположения о том, что этот термин значит.
Почему некоторые функции имеют префикс "native_"?
Чтобы предупредить пользователя, что результаты не будут портабельными. Названия сделаны намеренно корявыми, чтобы эти функции использовались только в случае действительной надобности.
Почему класс path не реализует operator== и другие операторы сравнения?
Не существует способа узнать,
представляют ли два объекта класса path один и
тот же файловый путь. К примеру, истинно ли
выражение path("abc") == path("ABC")?
Ответ - да, нет или может быть,
в зависимости от операционной системы (точнее -
от файловой системы). Если необходимо проверить
буквальное текстовое соответствие, то следует
использовать path::string().
Почему бы не поддерживать концепции специфических файловых систем, таких как posix_file_system или windows_file_system.
Портабельность - это одно из нескольких наиболее важных требований данной библиотеки. Получение некоторых выгод при использовании особенностей некоторых видов файловых систем не является целью библиотеки. Очевидно, нет необходимости иметь возможность манипулировать, скажем, путями классической Mac OS при работе программы на OpenVMS.
Более того, концепции типа "posix_file_system" очень нечеткие. Что случится, когда файловая система NTFS или ISO 9660 монтируется в каталоге на машине, работающей под управлением POSIX-подобной ОС, к примеру?
Почему бы не создать тип 'handle', и выполнять операции с каталогами и файлами через него?
Нет простого решения, удовлетворяющего требованию "портабельные операции в скриптовом стиле с файловой системой" в случае хэндлов. Но существуют файловые системы, которые выполняют операции с не-строковыми типами хэндлов. ОС Mac classic это пример системы, в которой операции со строковыми путями не являются удобными и естественными.
Применение хэндлов (типа данных для идентификации файла) может быть самым строгим подходом для реализации итераторов каталогов (См. постинг Jesse Jones' Jan 28, 2002). Однако, класс path проэволюционировал достаточно долго и он кажется достаточным для реализации типа итератора в каталогах.
Почему каталоги не рассматриваются как файлы?
Потому что каталоги нельзя портабельно и удобно открывать как файлы, используя средства ввода-вывода стандартной библиотеки C++ (stdio или fstream). Важным дополнительным аргументов является также то, что разделение концепций каталогов и файлов делает библиотеку более логичной. Некоторую проблему составляет наименование и описание аргументов функций.
|
Осмысленные имена аргументов |
||
|---|---|---|
|
Назначение аргумента |
Осмысленное имя, если директории являются файлами |
Осмысленное имя, если директории не являются файлами |
| путь либо к каталогу, либо к не-каталогу | path | path |
| путь к каталогу, но не к не-каталогу | directory_path | directory_path |
| путь к не-каталогу, но не к каталогу | non_directory_path | file_path |
Проблема заключается в том, что когда каталоги рассматриваются как файлы, non_directory_path - имя аргумента, и в документации соответственно написано "non-directory path", то описания становятся длинными и корявыми, поэтому применяется сокращение до path, что приводит к запутанности кода (если кроме этого не вызывает ошибки). Имена, которые возникают при реализации подхода "директории не файлы" более приемлемы и менее вероятно приведут к неправильному использованию.
Почему функции не-члены класса в operations.hpp такие низкоуровневые?
Для обеспечения средств для построения более высокоуровневых инструментов.
Продолжительные попытки добавить удобные функции в дополнение, или вместо, низкоуровневым функциям, закончились неудачей, потому что нет общепринятого набора базовых операций с однозначной семантикой. Попытки реализовать альтернативную семантику, через политики, задаваемые на стадии компиляции или во время работы программы, становились слишком сложными относительно обеспечиваемых ими выгод. С другой стороны, специфическая функциональность, необходимая для нескольких пробных приложений, может быть легко сконструирована пользователем из набора низкоуровневых функций. См. неудавшиеся попытки.
Не является ли непоследовательным предоставлять небольшое количество удобных функций?
Да, однако опыт применения данной библиотеки, POSIX, и Windows указывает на полезность некоторых удобных функций, и оказывается возможным реализовать для них простую, то общепризнанную семантику. К примеру, remove_all.
Почему библиотечные функции так строго подходят к ошибкам?
Безопасность. Политикой по умолчанию является обеспечение безопасности, нежели игнорирование ошибок. Это особенно важно, если учесть, что на многих компьютерных системах файлы и директории являются глобально разделяемыми ресурсами, подверженными неожиданным сбоям.
Почему ошибки вызывают генерацию исключений, вместо использования кодов возврата или переменной с кодом ошибки?
Безопасность. Возвращаемые значения или переменные-индикаторы ошибок зачастую игнорируются программистами. Исключения значительно труднее игнорировать, так как они вызывают аварийное прерывание программы, если не перехватываются, но в то же время позволяют аккуратно обработать ошибки при необходимости.
Почему доступ к атрибутам выполняется через методы, а не через таблицы свойств?
Для нескольких широко используемых атрибутов (существование, каталог или файл), простой синтаксис и гарантированное существование перевешивают другие соображения. Так как доступ к практически всем другим атрибутам является системно-зависимым, таблицы свойств рассматриваются как наиболее удобный способ доступа и модификаций, но с точки зрения дизайна лучше реализовать такую функиональность в отдельной библиотеке . (Историческое замечение: даже очевидно простой атрибут "только-для-чтения" оказывается настольно зависящим от системы, что не позволяет счтать его "гарантированно присутствующим")
Почему нет функции set_current_directory - для установки текущего каталога?
Глобальные переменные рассматриваются как небезопасные [wulf-shaw-73]. Пока мы не можем предохранить людей от стрельбы себе в ноги, мы не станем давать им в руку заряженное ружье, направленное прямо в большой палец ноги.
Почему нет функции для определения составных условий типа existing_directory?
После нескольких попыток, функции для проверки составных атрибутов признаны скользкой дорожкой, ступив на которую уже трудно остановиться?
Почему нет поддержки для юникода в файловых путях? Почему не используется std::wstring или даже шаблон с параметром?
Поддержка файловых путей с юникодом создают иллюзию платформонезависимости, которая на самом деле отсутствует. Поведение будет совершенно различным на операционных системах (Windows, к примеру), которые поддерживают юникод в именах файлов, и на системах, которые не имеют такой поддержки (POSIX). Предоставление функциональности, которая кажется обеспечивающей портабельность, но фактически вносит элемент зависимости поведения от реализации, крайне нежелательно. Более того, программы могут оказаться непортабельными для разных реализаций библиотеки с одной и той же операционной системой, не говоря уже о разных платформах.
Рабочая группа комитета стандартизации C++ обсуждала этот вопрос в деталях, и было решено (1) имена файлов, использующие не char в качестве типа символов являются крайне непортабельными, (2) не существует согласия по семантике преобразований между путями в юникоде и ASCII для систем, которые не поддерживают юникод, и (3) даже члены комитета, наиболее заинтересованные в использовании wchar_t символов для имен файлов, не уверены, что это хорошая идея с точки зрения портабельности.
[October, 2002 - PJ Plauger предложил схему преобразования на основе локали. Другие поддержали такой эксперимент].
Почему автоматически обнаруживаются ошибки с платформонезависимостью в именах файлов и каталогов в случаях, когда на самом деле ошибок нет?
Для многих пользователей автоматическое обнаружение ошибок на основе базовой грамматики файловых путей является важным умолчанием. В случаях, когда другие способы проверки (включая полное отсутствие проверки вообще) предпочтительны для всей программы, можно использовать функциональность для изменения поведения по умолчанию. Для случаев, когда другие способы проверки (включая полное отсутствие проверки вообще) предпочтительны для некоторого отдельного пути, способ проверки может быть указан в конструкторе path.
Функции проверки могут быть вызваны явно. Это дает еще один способ контроля.
Существующий дизайн делает проверку простой и автоматической для общего случая, хотя обеспечивает возможность явного управления проверкой при необходимости.
Почему нет более мощных средств проверки, таких как отложенная до момента реального использования пути?
Несколько (по крайней мере 6) дизайнов для проверки валидности имен было оценено, включая по крайней мере 4 полных реализации. Хотя причины отказа в каждом случае разные, все более мощные схемы проверки валидности имен нарушали простоту других аспектов библиотеки. В то время как проверка имен может быть полезной, увеличение сложности библиотеки неоправдано.
Почему в некоторых случаях манипуляции с путями выполняются функциями-членами класса, а иногда - обычными функциями?
Основное правило дизайна заключается в том, что число лексические операции выполняются методами класса path, а операции, выполняемые операционной системой, исполняются обычными функциями.
Почему нормализованная форма пути отличается от канонической формы?
Для таких операционных систем, как POSIX, в которых разрешены символические ссылки на каталоги, нормализованная форма пути может представлять иное место в файловой системе, чем каноническая форма. См. пример использования от Walter Landry.
Revised 26 мая, 2005
© Copyright Beman Dawes, 2002
Use, modification, and distribution are subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at www.boost.org/LICENSE_1_0.txt)
последняя правка: 26.05.2005
библиотека BOOST C++
http://www.boost.org
перевод
Elijah Koziev
www.solarix.ru