Исходной причиной начала работ над библиотекой Boost.Filesystem была ситуация с административными средствами Boost. Скрипты были написаны на языках Python, Perl, Bash, и командном языке Windows. Не было единого языка написания скриптов, знакомого и принятого всеми администраторами проекта Boost. Администраторы были опытными программистами C++ - так почему бы было не попробовать использовать C++ в качестве языка для написания скриптов?
Ключевой особенностью скриптов, отсутствующей в C++, была возможность выполнять портабельные операции с файловой системой. Библиотека Boost.Filesystem была разработана, чтобы заполнить отсутствие таких средств.
Намерение заключается не в состязании с традиционными скриптовыми языками, а в предоставлении средств в ситуации, когда C++ уже выбран для использования.
Иметь возможность писать портабельные операции над
файловой системой скриптового вида на современном
C++.
Объяснение: необходимость в этом имеет общий характер.
Трудность заключается в том, что это
невозможно на современном C++ или с использованием
библиотек в составе BOOST. Необходимость
достаточно остра, когда C++ является единственным
доступным для использования инструментом. Файловые операции
обеспечиваются многими языками, работающими на
множестве платформ, такими как Perl и Python, так
же как многими специфичными для платформ скриптовыми языками. Все ОС
предоставляют API для файловых операций, и POSIX-операции
становятся доступными для все большего количества ОС,
обычно не ассоциируемых с POSIX, таких как Mac, z/OS, или OS/390.
Нормально работать в описанных далее
реальных обстоятельствах.
Объяснение: Это не исследовательский проект. Необходима библиотека для
работы на современных платформах, включая
некоторые встроенные системы с ограниченными файловыми системами. Из-за
упора на портабельность, такая библиотека будет
гораздо более полезной, если ее стандартизировать.
Это означает возможность работать на более широком множестве платформ,
чем только Unix или Windows и их клоны.
Избегать опасных приемов программирования. В
частности, легко игнорируемые сообщения об ошибках
и использование глобальных переменных. Если
потенциально опасная возможность все-таки реализована,
следует ее пометить как опасную в документации.
Объяснение: обычно это обеспечивается "обычными требованиями библиотеки
BOOST...", однако упоминается явно еще раз,
так как зачастую скриптовые языки на разных платформах зависят от
легко игнорируемых сообщений об ошибках и глобальных переменных типа
"текущий рабочий каталог".
Следует так построить библиотеку,
чтобы она оставалась полезной даже на платформах,
где некоторая функциональность не может быть реализована имеющимися у
ОС и файловой системы средствами.
В частности, много полезной функциональности
должно быть портируемого даже на не-иерархические файловые системы.
Объяснение: Много функциональных возможностей,
которые не требуют иерархической структуры каталогов,
остаются полезными на файловых системах без иерархической структуры
каталогов. Существует много систем, в
частности встроенные системы, где даже очень
ограниченная функциональность библиотеки
Boost.Filesystem все еще полезна.
Безконфликтное взаимодействие со текущими средствами
ввода-вывода стандартной библиотеки C++. К примеру,
должна быть простая возможность использовать файловые
пути в конструкторах std::basic_fstream.
Объяснение: одним из наиболее распространенных применений
файловых операции является работа с путями при вводе-выводе. Поэтому
библиотека Boost.Filesystem должна легко
взаимодействовать со средствами ввода-вывода стандартной библиотеки.
Библиотека должна быть готова к стандартизации. Это
требование подразумевает, что интерфейс должен
быть близок к минимальному, и необходимая особая
тщательность в обеспечении портабельности.
Объяснение: отсутствие операций с файловой системой - это серьезный
пробел в текущем стандарте C++, причем кандидатов
на заполнение этого пробела нет. Библиотеки с
развитым интерфейсом сложны для переноса на разные платформы и поэтому вряд
ли подходят для принятия в качестве стандарта.
Применимы обычные
требования и рекомендации
библиотеки Boost.
Приветствуется, но не
требуется портабельность в путях.
Объяснение: Пути, которые вводятся
пользователем, не следует проверять на
портабельность синтаксиса.
Следует избегать иллюзии портабельности там,
где фактически она невозможна.
Объяснение: оставление важных параметров поведения неописанными или
"зависящими" от
реализации серьезно мешает программистам использоват
ь библиотеку, так как кажется,
что используемый код библиотеки портабелен, тогда
как фактически этот код непортабелен. Единственный случай,
когда такая не специфицированность поведения приемлема это если и
пользователи, и разработчики знают из других
источников,какое поведение требуется,
хотя по некоторым причинам его невозможно точно специфицировать.
Некоторые ОС работают с одним корнем дерева каталогов,
другие - с несколькими корнями.
Некоторые файловые системы оперируют короткими и
длинными формами имен файлов.
Некоторые файловые системы имеют разный синтаксис для
файловых путей и путей к каталогам.
Некоторые файловые системы имеют разные правила
корректности имен файлов и имен каталогов.
Некоторые файловые системы (ISO-9660, level 1, к
примеру) очень ограничены
(так называемые имена 8.3) в плане имен файлов.
Некоторые ОС допускают монтирование файловых системы
с разными характеристиками в одном дереве каталогов. Так что ISO-9660
или файловая система Windows могут оказаться поддеревом в дереве каталогов POSIX.
Юнокод допускается в путях для одних ОС и не допустим
для других.
Нет закона, по которому
иерархия каталогов должна записываться по правила "слева
направо от корня".
Некоторые файловые системы имеют концепцию "номера
версии" файла или "номера генерации", но
некоторые не имеют.
Не все ОС используют единый символ разделителя в
путях. Некоторые используют сдвоенную нотацию.
Типичное полностью специфицированное имя файла в OpenVMS может
выглядеть так:
DISK$SCRATCH:[GEORGE.PROJECT1.DAT]BIG_DATA_FILE.NTP;5
Общий синтаксис в OpenVMS:
Устройство:[разделенные.точкой.каталоги]имя.расширение;номер_версии
В общем случае очень трудно (если вообще возможно)
определить, указывают ли два пути на один и тот же
объект. К примеру, концепция равенства может
различаться для каждой порции пути - некоторые порции могут быть
чуствительны к локали, другие нет.
Чувствительность к регистру это свойство пути, а
не платформы в целом. Определение сопоставимых последовательностей (collating sequence)
еще более трудная задача.
Может возникнуть ситуация непредсказуемого изменения
используемого ресурса (race-conditions).
Деревья каталогов, каталоги,
файлы и атрибуты файлов разделяются между всеми нитями,
процессами и подключенными по сети компьютерами,
имеющими доступ к файловой системе. Этот список может включать
компьютеры на другом конце Земли либо на околопланетной орбите. Это
подразумевает, операции с файловой системой могут
завершаться ошибочно в самых непредсказуемых местах. К примеру:
assert( exists("foo") == exists("foo") ); //
may fail!
assert( is_directory("foo") == is_directory("foo"); //
may fail!
В данном случае файл может быть удален между вызовами
exists(). Во второй строке примера файл
может быть удален и затем заменен каталогом с тем же именем между двумя
вызовами is_directory().
Даже если приложение написано портабельно,
оно иногда может работать с путями в специфичном для платформы
формате; типичный пример - пользовательский ввод.
Символические ссылки
могут привести к тому, что каноническая и
нормальная форма представления пути будут указывать разные файлы или
каталоги. К примеру, задана иерархия каталогов //a/b/c, с символической
ссылкой /a с именем x,
указывающей на b/c. По правилам
Разрешения Путей POSIX (Pathname Resolution) путь "/a/x/.."
долженбыть разрешен в "/a/b". Если "/a/x/.."
был сперва нормализован в "/a", результат мог бы быть
некорректным. (Случай предоставил Walter Landry.)
Описанные выше Требования и Реальность в значительной степени касаются дизайна интерфейса библиотеки. В частности, желание сделать писать код с скриптовом стиле требует больших усилий, чтобы гарантировать нормальную работу выражений типа exists( "foo" ).
Более детальное описание причин реализованного дизайна библиотеки читайте в разделе часто задаваемых вопросов.
В дизайн класса path положено несколько ключевых идей:
Разделение входного формата, внутреннего представления (vector<string> или другая последовательность), и выходных форматов.
Предоставление двух входных форматов (обобщенный и специфичный для ОС) ликвидирует основной тупик дизайна.
Предоставление нескольких выходных форматов решило другую группу ранее неразрешимых проблем.
Несколько неочевидных функций (в частности, разбиение и соединение) требуются для поддержки портабельного кода. (Peter Dimov, Thomas Witt, Glen Knowles, другие.)
Трудной задачей оказалось создание механизма проверки ошибок. Одной из ключевых идей была такая: с именами файлов и каталогов портабельность не является универсальной истиной. Скорее, программист должен обдумать такой вопрос "Для каких ОС я хотел бы получить портабельность?". Обеспечив поддержку нескольких ответов на этот вопрос, библиотека Boost.Filesystem Library побуждает программистов задавать такой вопрос с самого начала.
operations.hpp
Оригинальная реализация dir_it (автор - Dietmar Kühl) поддерживала работу с юникодом в именах файлов каталогов. От этой поддержки отказались после интенсивных дискуссий среди членов Рабочей Группы Библиотеки, когда не удалось разработать портабельную семантику для юникода на системах, которые его не поддерживают. См. ЧАВО.
Прежние попытки разработать дизайн интерфейса использовали явно называемые функции, выполняющие большое количество удобных операций, без опций времени исполнения или времени компиляции. Было так много имен функций, что их было сложно использовать, и интерфейс был намного более громоздкий. Все выгоды показались скорее теоретическими, чем реальными.
Попытки реализации, основанные на флагах и опциях времени компиляции (а не времени исполнения), через политики или параметры шаблона, оказались столь запутанными, что от них пришлось отказаться, после затраченного времени и сил. Необходимость полностью квалифицировать атрибуты или имена опций с помощью пространств имен, даже через синонимы, сделала реализацию на основе параметров шаблонов очень неуклюжей. Это стало понятно только после начала практического использования библиотеки.
Еще один набор вспомогательных функций (к примеру, remove с подтверждением, рекурсией и другими опциями, плюс команда-предикат для отбора файлов, а также другие опции фильтрации) был отброшен по причине слишком сложного использования.
Остался только набор низкоуровневых операций, из которых пользователь может собрать более сложные вспомогательные функции, плюс очень небольшое число вспомогательных функций, которые оказались достаточно полезными для включения в библиотеку Boost.Filesystem.
path.hpp
Было так много отвергнутых реализаций класса path, что я потерял им счет. Использующие политики шаблонные классы (policy-based class templates) разных типов, передаваемые в конструкторы во время исполнения управляющие флаги, специфичные для операций политики времени исполнения - все они были рассмотрены, зачастую реализованы и в конце концов отброшены как слишком сложные при небольших сулимых выгодах.
error checking
Несколько дизайнов для средств проверки ошибок было отброшено в ходе разработки библиотеки после экспериментов с реализациями. В частности, была опробована схема полностью автоматической обработки ошибок. Но оказалось, что полностью автоматическая проверка ошибок делает общий дизайн библиотеки намного более сложным.
Некоторые предложенные дизайны связывали механизмы обработки ошибок с путями, другие с функциями для выполнения операций. Дизайн проверки ошибок с использованием частичной специализации шаблонов и применением policy был частично реализован, а затем отброшен как слишком сложный для повседневных программ в духе скриптов.
Конечный дизайн, который частично опирается на явном вызове функций проверки ошибок, оказался намного более простым и понятным, хотя он в некоторой степени зависит от дисциплины программиста. Но это должно позволить программисту, который нуждается в портабельность, быть уверенным, что его программа будет корректно работать на выбранных целевых платформах.
[IBM-01] IBM Corporation, z/OS V1R3.0 C/C++ Run-Time Library Reference, SA22-7821-02, 2001, http://www-1.ibm.com/servers/eserver/zseries/zos/bkserv/
[ISO-9660] International Standards Organization, 1988.
[MSDN] Microsoft Platform SDK for Windows, Storage Start Page, http://msdn.microsoft.com/library/en-us/fileio/base/storage_start_page.asp
[POSIX-01] IEEE Std 1003.1-2001/ISO/IEC 9945:2002 , http://www.unix-systems.org/version3/. The ISO JTC1/SC22/WG15 - POSIX homepage is http://std.dkuug.dk/JTC1/SC22/WG15/.
[URI] RFC-2396, Uniform Resource Identifiers (URI): Generic Syntax, http://www.ietf.org/rfc/rfc2396.txt
[Wulf-Shaw-73] William Wulf, Mary Shaw, Global Variable Considered Harmful, ACM SIGPLAN Notices, 8, 2, 1973, pp. 23-34
© 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)
последняя правка: 17.09.2005
библиотека BOOST C++
http://www.boost.org
перевод
Elijah Koziev
www.solarix.ru