Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Filesystem Tutorial

Boost , ,

boost.png (6897 bytes) Filesystem Tutorial
Home  Учебник  Ссылка  FAQ  Релизы  Портативность  V3 Intro  V3 Design  Пренебрежение  Отчеты об ошибках  

Введение
Предварительные замечания
Сообщение о размере файла - (tut1.cpp)
Использование запросов состояния для определения существования и типа файла - (tut2.cpp)
Итерация каталогов плюс улавливающие исключения - (tut3.cpp)
Использование пути разложения, плюс результаты сортировки - (tut4.cpp)
Класс пути: Конструкторы, включая Unicode - (tut5.cpp)
Класс пути: Общий формат против Нативного формата
Классовый путь: итераторы, наблюдатели, состав, разложение и запрос - (path_info.cpp)
Ошибка

Introduction

В этом руководстве разрабатывается небольшая программа командной строки для перечисления информации о файлах и каталогах - по сути, это упрощенная версия команд POSIX<ls>или Windows<dir>. Мы начнем с самой простой версии и перейдем к более сложной функциональности. По пути мы рассмотрим темы, которые вам нужно знать, чтобы понять Boost.Filesystem.

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

Preliminaries

Установите дистрибутив Boost, если вы еще этого не сделали. См.Начало работы.

Это руководство предполагает, что вы собираетесь собирать и тестировать примеры с использованием предоставленных сценариев. Очень рекомендуется.

Если вы планируете собирать и тестировать примеры, но не используете сценарии, убедитесь, что ваша настройка сборки знает, где найти или построить библиотечные двоичные файлы Boost.

Запустите интерпретатор командной строки и введите следующие команды:

Ubuntu Linux
<
$ cdboost-root/libs/filesystem/example/test
$ ./setup.sh
Copying example programs...
$ ./build.sh
Compiling example programs...
$ ./tut1
Usage: tut1 path
>
 
Microsoft Windows
<
>cdboost-root\libs\filesystem\example\test
>setup
Copying example programs...
>build
Compiling example programs...
>tut1
Usage: tut1 path
>

Если<tut1>команда выводит "<Usage: tut1 path>", все хорошо. Набор учебных примеров программ был скопирован<setup>до<boost-root></libs/filesystem/example/test>и затем построен. Вам рекомендуется модифицировать и экспериментировать с ними по мере продвижения учебника. Призывайте<build>сценарий снова, чтобы восстановить, или призывайте<b2>напрямую.

Если что-то не сработало, вот несколько советов по устранению неполадок:

  • Если исполняемый файл программыb2не найден, проверьте переменную окружающей среды или посмотритеНачало работы.
     
  • Посмотрите наb2.log, чтобы попытаться обнаружить признаки проблемы.

Reporting the size of a file - (tut1.cpp)

Давайте начнем. Наша первая примерная программаtut1.cppсообщает о размере файла:

<
#include <iostream>
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    std::cout << "Usage: tut1 path\n";
    return 1;
  }
  std::cout << argv[1] << " " << file_size(argv[1]) << '\n';
  return 0;
}
>#include <iostream> #include <boost/filesystem.hpp> using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { std::cout << "Usage: tut1 path\n"; return 1; } std::cout << argv[1] << " " << file_size(argv[1]) << '\n'; return 0; } [ORIG_END] -->

Функция Boost.Filesystem<file_size>возвращает<uintmax_t>, содержащую размер файла, названного аргументом. Декларация выглядит так:

uintmax_t file_size(const path& p); 

На данный момент все, что вам нужно знать, это то, что<class path>имеет конструкторы, которые принимают<const char *>и другие типы струн. (Если вы не можете дождаться, чтобы узнать больше, перейдите кклассный путьраздел учебника.)

Пожалуйста, потратьте минуту, чтобы опробовать<tut1>в вашей системе, используя файл, который, как известно, существует, например<tut1.cpp>. Вот как выглядят результаты на двух разных операционных системах:

Ubuntu Linux
$ ./tut1 tut1.cpp
tut1.cpp 569
$ ls -l tut1.cpp
-rw-rw-r-- 1 beman beman 569 Jul 26 12:04 tut1.cpp
 
Microsoft Windows
>tut1 tut1.cpp
tut1.cpp 592
>dir tut1.cpp
...
07/26/2015 07:20 AM 592 tut1.cpp
...

Пока что так хорошо. Размеры Linux и Windows отличаются, потому что в тестах Linux использовались окончания строк<"\n">, а в тестах Windows использовались окончания строк<"\r\n">. Размеры отчетов могут отличаться от приведенных выше, если были внесены изменения<tut1.cpp>.

Теперь попробуйте еще раз, но дайте путь, которого не существует:

Ubuntu Linux
$ ./tut1 foo
terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
what(): boost::filesystem::file_size: No such file or directory: "foo"
Aborted (core dumped)
 
Microsoft Windows
>tut1 foo

Исключение бросается;
точная форма ответа зависит от опций системы Windows.

Что происходит? В текущем каталоге нет файла с именем<foo>, поэтому по умолчанию выбрасывается исключение. См.Отчет об ошибках, чтобы узнать об отчетности об ошибках с помощью кодов ошибок, а не исключений.

Попробуйте вот это:

Ubuntu Linux
<
$ ./tut1 .
terminate called after throwing an instance of 'boost::filesystem::filesystem_error'
what(): boost::filesystem::file_size: Operation not permitted: "."
Aborted (core dumped)
>
 
Microsoft Windows
>tut1 .

Исключение бросается;
точная форма ответа зависит от опций системы Windows.

Текущий каталог существует, но<file_size()>работает с обычными файлами, а не каталогами, поэтому снова бросается исключение.

Мы разберемся с этими ситуациями в<tut2.cpp>.

Using status queries to determine file existence and type - (tut2.cpp)

Повышаю. Файловая система включает в себя функции запроса состояния, такие как< exists>,<is_directory>и< is_regular_file>. Они возвращаются<bool>и вернутся<true>, если будет выполнено условие, описанное их именем. В противном случае они возвращаются<false>, в том числе, когда какой-либо элемент аргумента пути не может быть найден.

tut2.cppиспользует несколько функций запроса состояния, чтобы справиться с несуществующими файлами и с различными типами файлов:

<
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    cout << "Usage: tut2 path\n";
    return 1;
  }
  path p(argv[1]);  // avoid repeated path construction below
  if (exists(p))    // does path p actually exist?
  {
    if (is_regular_file(p))        // is path p a regular file?
      cout << p << " size is " << file_size(p) << '\n';
    else if (is_directory(p))      // is path p a directory?
      cout << p << " is a directory\n";
    else
      cout << p << " exists, but is not a regular file or directory\n";
  }
  else
    cout << p << " does not exist\n";
  return 0;
}
>#include <iostream> #include <boost/filesystem.hpp> using namespace std; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { cout << "Usage: tut2 path\n"; return 1; } path p(argv[1]); // avoid repeated path construction below if (exists(p)) // does path p actually exist? { if (is_regular_file(p)) // is path p a regular file? cout << p << " size is " << file_size(p) << '\n'; else if (is_directory(p)) // is path p a directory? cout << p << " is a directory\n"; else cout << p << " exists, but is not a regular file or directory\n"; } else cout << p << " does not exist\n"; return 0; } [ORIG_END] -->

Попробуйте вот это:

Ubuntu Linux
$ ./tut2 tut2.cpp
"tut2.cpp" size is 997
$ ./tut2 foo
"foo" does not exist
$ ./tut2 .
"." is a directory
 
Microsoft Windows
>tut2 tut2.cpp
tut2.cpp size is 1039
>tut2 foo
"foo" does not exist
>tut2 .
"." is a directory

Несмотря на то, что tut2 работает нормально в этих тестах, выход менее чем удовлетворителен для каталога. Обычно мы хотели бы видеть список содержимого каталога. В<tut3.cpp>мы увидим, как повторять каталоги.

Но сначала давайте попробуем еще один тест:

Ubuntu Linux
$ ls /home/jane/foo
ls: cannot access /home/jane/foo: No such file or directory
$ ./tut2 /home/jane/foo
terminate called after throwing an instance of 'boost::
filesystem::filesystem_error>'
   what(): boost::filesystem::status: Permission denied:
     "/home/jane/foo"
Aborted
 
Microsoft Windows
>dir e:\
The device is not ready.
>tut2 e:\

An exception is thrown;
the exact form of the response depends on Windows system options.

В системе Linux тест запускался с аккаунта, у которого не было разрешения на доступ</home/jane/foo>. В системе Windows< e:>был компакт-диск, который не был готов. Конечным пользователям не нужно интерпретировать отчеты о загадочных исключениях, поэтому, когда мы перейдем к<tut3.cpp>, мы также увеличим надежность кода.

Directory iteration plus catching exceptions - (tut3.cpp)

Класс Boost.Filesystem< directory_iterator>- это именно то, что нам нужно здесь. Это соответствует общей схеме стандартной библиотеки<istream_iterator>. Построенный с пути, он повторяется над содержимым каталога. По умолчанию построенный<directory_iterator>действует как конечный итератор.

Тип значения<directory_iterator>равен< directory_entry>. Объект< directory_entry>содержит<path>и<file_status>информацию. Объект< directory_entry>может быть использован непосредственно, но также может быть передан<path>аргументам в вызовах функций.

Другая необходимость заключается в повышении надежности перед лицом многих видов ошибок, которые могут повлиять на работу файловой системы. Мы могли бы сделать это на уровне каждого вызова на повышение. Функция файловой системы (см.Отчетность об ошибках), но для простотыtut3.cppиспользует общий блок проб/лов.

<
#include <iostream>
#include <boost/filesystem.hpp>
using std::cout;
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    cout << "Usage: tut3 path\n";
    return 1;
  }
  path p (argv[1]);
  try
  {
    if (exists(p))
    {
      if (is_regular_file(p))
        cout << p << " size is " << file_size(p) << '\n';
      else if (is_directory(p))
      {
        cout << p << " is a directory containing:\n";
        for (directory_entry& x : directory_iterator(p))
          cout << "    " << x.path() << '\n'; 
      }
      else
        cout << p << " exists, but is not a regular file or directory\n";
    }
    else
      cout << p << " does not exist\n";
  }
  catch (const filesystem_error& ex)
  {
    cout << ex.what() << '\n';
  }
  return 0;
}
>#include <iostream> #include <boost/filesystem.hpp> using std::cout; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { cout << "Usage: tut3 path\n"; return 1; } path p (argv[1]); try { if (exists(p)) { if (is_regular_file(p)) cout << p << " size is " << file_size(p) << '\n'; else if (is_directory(p)) { cout << p << " is a directory containing:\n"; for (directory_entry& x : directory_iterator(p)) cout << " " << x.path() << '\n'; } else cout << p << " exists, but is not a regular file or directory\n"; } else cout << p << " does not exist\n"; } catch (const filesystem_error& ex) { cout << ex.what() << '\n'; } return 0; } [ORIG_END] -->

Дайте<tut3>попытку, передав ей путь к каталогу в качестве аргумента командной строки. Вот забег на кассе ветки разработки Boost Git, за которым следует повторение тестовых случаев, вызвавших исключения в Linux и Windows:

Ubuntu Linux
$ ./tut3 ~/boost/develop
    "/home/beman/boost/develop" is a directory containing:
    "/home/beman/boost/develop/rst.css"
    "/home/beman/boost/develop/boost"
    "/home/beman/boost/develop/boost.png"
    "/home/beman/boost/develop/libs"
    "/home/beman/boost/develop/doc"
    "/home/beman/boost/develop/project-config.jam.2"
    "/home/beman/boost/develop/.gitmodules"
    "/home/beman/boost/develop/boostcpp.py"
    "/home/beman/boost/develop/.travis.yml"
    "/home/beman/boost/develop/.gitattributes"
    "/home/beman/boost/develop/index.htm"
    "/home/beman/boost/develop/index.html"
    "/home/beman/boost/develop/bjam"
    "/home/beman/boost/develop/project-config.jam.1"
    "/home/beman/boost/develop/LICENSE_1_0.txt"
    "/home/beman/boost/develop/.git"
    "/home/beman/boost/develop/tools"
    "/home/beman/boost/develop/stage"
    "/home/beman/boost/develop/boostcpp.jam"
    "/home/beman/boost/develop/Jamroot"
    "/home/beman/boost/develop/.gitignore"
    "/home/beman/boost/develop/INSTALL"
    "/home/beman/boost/develop/more"
    "/home/beman/boost/develop/bin.v2"
    "/home/beman/boost/develop/project-config.jam"
    "/home/beman/boost/develop/boost-build.jam"
    "/home/beman/boost/develop/bootstrap.bat"
    "/home/beman/boost/develop/bootstrap.sh"
    "/home/beman/boost/develop/status"
    "/home/beman/boost/develop/boost.css"
 
Microsoft Windows
>tut3 \boost\develop
"\boost\develop" is a directory containing:
    "\boost\develop\.git"
    "\boost\develop\.gitattributes"
    "\boost\develop\.gitignore"
    "\boost\develop\.gitmodules"
    "\boost\develop\.travis.yml"
    "\boost\develop\bin.v2"
    "\boost\develop\boost"
    "\boost\develop\boost-build.jam"
    "\boost\develop\boost.css"
    "\boost\develop\boost.png"
    "\boost\develop\boostcpp.jam"
    "\boost\develop\boostcpp.py"
    "\boost\develop\bootstrap.bat"
    "\boost\develop\bootstrap.sh"
    "\boost\develop\doc"
    "\boost\develop\index.htm"
    "\boost\develop\index.html"
    "\boost\develop\INSTALL"
    "\boost\develop\Jamroot"
    "\boost\develop\libs"
    "\boost\develop\LICENSE_1_0.txt"
    "\boost\develop\more"
    "\boost\develop\project-config.jam"
    "\boost\develop\rst.css"
    "\boost\develop\stage"
    "\boost\develop\status"
    "\boost\develop\tools"
>tut3 e:\
boost::filesystem::status: The device is not ready: "e:\"

Неплохо, но мы можем сделать дальнейшие улучшения:

  • Список было бы намного легче читать, если бы отображалось только имя файла, а не полный путь.
     
  • Список Linux не сортируется. Это потому, что порядок итерации каталогов не определен. Заказ зависит от базовой операционной системы API и особенностей файловой системы. Поэтому мы должны сами сортировать результаты.

В следующих разделах показано, как эти изменения происходят, так что читайте дальше!

Using path decomposition, plus sorting results - (tut4.cpp)

Для каталоговtut4.cppстроит< std::vector>всех записей, а затем сортирует его перед написанием< cout>.

<
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/filesystem.hpp>
using std::cout;
using namespace boost::filesystem;
int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    cout << "Usage: tut4 path\n";
    return 1;
  }
  path p (argv[1]);
  try
  {
    if (exists(p))
    {
      if (is_regular_file(p))
        cout << p << " size is " << file_size(p) << '\n';
      else if (is_directory(p))
      {
        cout << p << " is a directory containing:\n";
        std::vector<std::string> v;
        for (auto&& x : directory_iterator(p))
          v.push_back(x.path().filename().string()); 
        std::sort(v.begin(), v.end());  
        for (auto&& x : v)
          cout << "    " << x << '\n';
      }
      else
        cout << p << " exists, but is not a regular file or directory\n";
    }
    else
      cout << p << " does not exist\n";
  }
  catch (const filesystem_error& ex)
  {
    cout << ex.what() << '\n';
  }
  return 0;
}
>#include <iostream> #include <vector> #include <algorithm> #include <boost/filesystem.hpp> using std::cout; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { cout << "Usage: tut4 path\n"; return 1; } path p (argv[1]); try { if (exists(p)) { if (is_regular_file(p)) cout << p << " size is " << file_size(p) << '\n'; else if (is_directory(p)) { cout << p << " is a directory containing:\n"; std::vector<std::string> v; for (auto&& x : directory_iterator(p)) v.push_back(x.path().filename().string()); std::sort(v.begin(), v.end()); for (auto&& x : v) cout << " " << x << '\n'; } else cout << p << " exists, but is not a regular file or directory\n"; } else cout << p << " does not exist\n"; } catch (const filesystem_error& ex) { cout << ex.what() << '\n'; } return 0; } [ORIG_END] -->

Ключевое различие между<tut3.cpp>и<tut4.cpp>заключается в том, что происходит в цикле итерации каталогов. Мы изменились:

cout << " " << *it << '\n';   // *it returns a directory_entry,

к:

path fn = it->path().filename();   // extract the filename from the path
v.push_back(fn);                   // push into vector for later sorting

<path()>является<directory_entry>функцией наблюдателя.< filename()>является одной из нескольких функций разложения пути. Он извлекает часть имени файла (147) из пути (148). Эти функции разложения более полно изучены в. Итераторы пути, наблюдатели, состав, разложение и запросчасти этого учебника.

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

v.push_back(it->path().filename()); // we only care about the filename

Вот результаты испытания<tut4.cpp>:

Ubuntu Linux
<
$ ./tut4  v
>
 
Microsoft Windows
<
$ ./tut4 ~/boost/develop
"/home/beman/boost/develop" is a directory containing:
    .git
    .gitattributes
    .gitignore
    .gitmodules
    .travis.yml
    INSTALL
    Jamroot
    LICENSE_1_0.txt
    bin.v2
    boost
    boost-build.jam
    boost.css
    boost.png
    boostcpp.jam
    boostcpp.py
    bootstrap.bat
    bootstrap.sh
    doc
    index.htm
    index.html
    libs
    more
    project-config.jam
    project-config.jam.1
    project-config.jam.2
    rst.css
    stage
    status
    tools
>

Это завершает основную часть этого учебника. Если вы еще не проработалиКлассовая дорожкаразделов этого учебника, копайтесь в них сейчас. Раздел«Отчет об ошибках»также может представлять интерес, хотя его можно пропустить, если вы глубоко не обеспокоены проблемами обработки ошибок.

Class path: Constructors, including Unicode - (tut5.cpp)

Традиционный C-интерфейсы проходят пути в виде аргументов<const char*>. Интерфейсы C++ могут добавлять<const std::string&>перегрузок, но добавление перегрузок становится несостоятельным, если необходимо поддерживать широкие символы, контейнеры и диапазоны итераторов.

Прохождение траекторий как<const path&>аргументов намного проще, но гораздо более гибко, потому что сам класс<path>гораздо более гибок:

  1. Классpathподдерживает несколько типов символов и кодировок, включая Unicode, для облегчения интернационализации.
  2. Классpathподдерживает несколько типов источников, таких как итераторы для нулевых завершенных последовательностей, диапазоны итераторов, контейнеры (включаяstd::basic_string) иdirectory_entry, поэтому функциям, принимающим пути, не нужно предоставлять несколько перегрузок.
  3. Классpathподдерживает как нативные, так и общие форматы имени пути, поэтому программы могут быть переносимы между операционными системами, но использовать нативные форматы там, где это желательно.
  4. Классpathпредоставляет полный набор итераторов, наблюдателей, функций композиции, разложения и запроса, что делает манипуляции с именем пути легкими, удобными, надежными и портативными.

Вот как работают (1) и (2). Конструкторы классовых путей, задания и приложения имеют шаблоны членов для источников. Например, вот конструкторы, которые берут источники:

template <class Source>
  path(Source const& source);
template <class InputIterator>
  path(InputIterator begin, InputIterator end);

Давайте посмотрим на небольшую программу, которая показывает, насколько комфортен класс<path>с узкими и широкими символами в строках C-стиля, строках C++ и с помощью итераторов C++:

<
#include <boost/filesystem/fstream.hpp>
#include <string>
#include <list>
namespace fs = boost::filesystem;
int main()
{
  // \u263A is "Unicode WHITE SMILING FACE = have a nice day!"
  std::string narrow_string ("smile2");
  std::wstring wide_string (L"smile2\u263A");
  std::list<char> narrow_list;
  narrow_list.push_back('s');
  narrow_list.push_back('m');
  narrow_list.push_back('i');
  narrow_list.push_back('l');
  narrow_list.push_back('e');
  narrow_list.push_back('3');
  std::list<wchar_t> wide_list;
  wide_list.push_back(L's');
  wide_list.push_back(L'm');
  wide_list.push_back(L'i');
  wide_list.push_back(L'l');
  wide_list.push_back(L'e');
  wide_list.push_back(L'3');
  wide_list.push_back(L'\u263A');
  { fs::ofstream f("smile"); }
  { fs::ofstream f(L"smile\u263A"); }
  { fs::ofstream f(narrow_string); }
  { fs::ofstream f(wide_string); }
  { fs::ofstream f(narrow_list); }
  { fs::ofstream f(wide_list); }
  narrow_list.pop_back();
  narrow_list.push_back('4');
  wide_list.pop_back();
  wide_list.pop_back();
  wide_list.push_back(L'4');
  wide_list.push_back(L'\u263A');
  { fs::ofstream f(fs::path(narrow_list.begin(), narrow_list.end())); }
  { fs::ofstream f(fs::path(wide_list.begin(), wide_list.end())); }
  return 0;
}
>#include <boost/filesystem/fstream.hpp> #include <string> #include <list> namespace fs = boost::filesystem; int main() { // \u263A is "Unicode WHITE SMILING FACE = have a nice day!" std::string narrow_string ("smile2"); std::wstring wide_string (L"smile2\u263A"); std::list<char> narrow_list; narrow_list.push_back('s'); narrow_list.push_back('m'); narrow_list.push_back('i'); narrow_list.push_back('l'); narrow_list.push_back('e'); narrow_list.push_back('3'); std::list<wchar_t> wide_list; wide_list.push_back(L's'); wide_list.push_back(L'm'); wide_list.push_back(L'i'); wide_list.push_back(L'l'); wide_list.push_back(L'e'); wide_list.push_back(L'3'); wide_list.push_back(L'\u263A'); { fs::ofstream f("smile"); } { fs::ofstream f(L"smile\u263A"); } { fs::ofstream f(narrow_string); } { fs::ofstream f(wide_string); } { fs::ofstream f(narrow_list); } { fs::ofstream f(wide_list); } narrow_list.pop_back(); narrow_list.push_back('4'); wide_list.pop_back(); wide_list.pop_back(); wide_list.push_back(L'4'); wide_list.push_back(L'\u263A'); { fs::ofstream f(fs::path(narrow_list.begin(), narrow_list.end())); } { fs::ofstream f(fs::path(wide_list.begin(), wide_list.end())); } return 0; } [ORIG_END] -->

Тестирование<tut5>:

Ubuntu Linux
$ ./tut5
$ ls smile*
smile smile☺ smile2 smile2☺ smile3 smile3☺ smile4 smile4☺
 
Microsoft Windows
>tut5
>dir /b smile*
smile
smile2
smile2☺
smile3
smile3☺
smile4
smile4☺
smile☺

Точный внешний вид улыбающегося лица будет зависеть от шрифта, размера шрифта и других настроек окна командной строки. Вышеуказанные тесты были запущены с Ubuntu 14.04 и Windows 7, US Edition. Если вы не получили вышеуказанных результатов, взгляните на каталог<boost-root/libs/filesystem/example/test>с помощью файлового браузера GUI вашей системы, такого как Linux Nautilus, Mac OS X Finder или Windows Explorer. Они, как правило, более удобны с международными наборами символов, чем переводчики командной строки.

Класс<path>заботится о любом типе символов или преобразованиях кодирования, требуемых конкретной операционной системой. Таким образом, как показывает< tut5>, не проблема передать широкую строку символа на повышение. Операционная функция файловой системы, даже если базовая операционная система использует узкие символы, и наоборот. То же самое относится к функциям, которые используют аргументы<const path&>.

Класс<path>также обеспечивает синтаксис пути, переносимый через операционные системы, итераторы элементов и функции наблюдателя, композиции, разложения и запроса для управления элементами пути. Следующий раздел этого учебника посвящен синтаксису пути.

Class path: Generic format vs. Native format

Класс<path>имеет дело с двумя различными форматами имени пути - общим форматом и родным форматом. Для POSIX-подобных файловых систем эти форматы одинаковы. Но для пользователей Windows и других не-POSIX файловых систем различие важно. Даже программисты, пишущие для POSIX-подобных систем, должны понимать разницу, если они хотят, чтобы их код был переносим на не-POSIX-системы.

Общий форматявляется знакомым форматом</my_directory/my_file.txt>, используемым POSIX-подобными операционными системами, такими как варианты Unix, Linux и Mac OS X. Windows также распознает общий формат, и он является основой для знакомого формата URL-адреса в Интернете. Сепаратор каталогов — это всегда один или несколько символов слэша.

Нативный форматявляется форматом, определенным конкретной операционной системой. Для Windows слэш или бэкслэш можно использовать в качестве символа разделителя каталогов, поэтому</my_directory\my_file.txt>будет работать нормально. Конечно, если вы напишете это в строке C++ буквально, она станет<"/my_directory\\my_file.txt">.

Если в системе Windows в имени пути появляется спецификатор диска или обратная слэш, он всегда рассматривается как родной формат.

Класс<path>имеет функции наблюдателя, которые позволяют получить представление строки объекта пути либо в нативном формате, либо в общем формате. Смотритеследующий раздел.

Различие между общим форматом и нативным форматом важно при общении с нативным API в стиле C и с пользователями. Оба, как правило, ожидают пути в родном формате и могут быть спутаны общим форматом. Общий формат отлично подходит для написания портативных программ, которые работают независимо от операционной системы.

Следующий раздел посвящен наблюдателям класса<path>, составу, разложению, запросу и итерации элементов пути.

Class path: Iterators, observers, composition, decomposition, and query - (path_info.cpp)

Программа<path_info.cpp>полезна для изучения того, как работают итераторы классов<path>, наблюдатели, состав, разложение и функции запросов в вашей системе. Это одна из программ, построенных сценариями<build.sh>и<build.bat>:

<
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace boost::filesystem;
const char * say_what(bool b) { return b ? "true" : "false"; }
int main(int argc, char* argv[])
{
  if (argc < 2)
  {
    cout << "Usage: path_info path-element [path-element...]\n"
            "Composes a path via operator/= from one or more path-element arguments\n"
            "Example: path_info foo/bar baz\n"
#            ifdef BOOST_POSIX_API
            "         would report info about the composed path foo/bar/baz\n";
#            else  // BOOST_WINDOWS_API
            "         would report info about the composed path foo/bar\\baz\n";
#            endif
    return 1;
  }
  path p;
  for (; argc > 1; --argc, ++argv)
    p /= argv[1];  // compose path p from the command line arguments
  cout  <<  "\ncomposed path:\n";
  cout  <<  "  operator<<()---------: " << p << "\n";
  cout  <<  "  make_preferred()-----: " << p.make_preferred() << "\n";
  cout << "\nelements:\n";
  for (auto element : p)
    cout << "  " << element << '\n';
  cout  <<  "\nobservers, native format:" << endl;
# ifdef BOOST_POSIX_API
  cout  <<  "  native()-------------: " << p.native() << endl;
  cout  <<  "  c_str()--------------: " << p.c_str() << endl;
# else  // BOOST_WINDOWS_API
  wcout << L"  native()-------------: " << p.native() << endl;
  wcout << L"  c_str()--------------: " << p.c_str() << endl;
# endif
  cout  <<  "  string()-------------: " << p.string() << endl;
  wcout << L"  wstring()------------: " << p.wstring() << endl;
  cout  <<  "\nobservers, generic format:\n";
  cout  <<  "  generic_string()-----: " << p.generic_string() << endl;
  wcout << L"  generic_wstring()----: " << p.generic_wstring() << endl;
  cout  <<  "\ndecomposition:\n";
  cout  <<  "  root_name()----------: " << p.root_name() << '\n';
  cout  <<  "  root_directory()-----: " << p.root_directory() << '\n';
  cout  <<  "  root_path()----------: " << p.root_path() << '\n';
  cout  <<  "  relative_path()------: " << p.relative_path() << '\n';
  cout  <<  "  parent_path()--------: " << p.parent_path() << '\n';
  cout  <<  "  filename()-----------: " << p.filename() << '\n';
  cout  <<  "  stem()---------------: " << p.stem() << '\n';
  cout  <<  "  extension()----------: " << p.extension() << '\n';
  cout  <<  "\nquery:\n";
  cout  <<  "  empty()--------------: " << say_what(p.empty()) << '\n';
  cout  <<  "  is_absolute()--------: " << say_what(p.is_absolute()) << '\n';
  cout  <<  "  has_root_name()------: " << say_what(p.has_root_name()) << '\n';
  cout  <<  "  has_root_directory()-: " << say_what(p.has_root_directory()) << '\n';
  cout  <<  "  has_root_path()------: " << say_what(p.has_root_path()) << '\n';
  cout  <<  "  has_relative_path()--: " << say_what(p.has_relative_path()) << '\n';
  cout  <<  "  has_parent_path()----: " << say_what(p.has_parent_path()) << '\n';
  cout  <<  "  has_filename()-------: " << say_what(p.has_filename()) << '\n';
  cout  <<  "  has_stem()-----------: " << say_what(p.has_stem()) << '\n';
  cout  <<  "  has_extension()------: " << say_what(p.has_extension()) << '\n';
  return 0;
}
>#include <iostream> #include <boost/filesystem.hpp> using namespace std; using namespace boost::filesystem; const char * say_what(bool b) { return b ? "true" : "false"; } int main(int argc, char* argv[]) { if (argc < 2) { cout << "Usage: path_info path-element [path-element...]\n" "Composes a path via operator/= from one or more path-element arguments\n" "Example: path_info foo/bar baz\n" # ifdef BOOST_POSIX_API " would report info about the composed path foo/bar/baz\n"; # else // BOOST_WINDOWS_API " would report info about the composed path foo/bar\\baz\n"; # endif return 1; } path p; for (; argc > 1; --argc, ++argv) p /= argv[1]; // compose path p from the command line arguments cout << "\ncomposed path:\n"; cout << " operator<<()---------: " << p << "\n"; cout << " make_preferred()-----: " << p.make_preferred() << "\n"; cout << "\nelements:\n"; for (auto element : p) cout << " " << element << '\n'; cout << "\nobservers, native format:" << endl; # ifdef BOOST_POSIX_API cout << " native()-------------: " << p.native() << endl; cout << " c_str()--------------: " << p.c_str() << endl; # else // BOOST_WINDOWS_API wcout << L" native()-------------: " << p.native() << endl; wcout << L" c_str()--------------: " << p.c_str() << endl; # endif cout << " string()-------------: " << p.string() << endl; wcout << L" wstring()------------: " << p.wstring() << endl; cout << "\nobservers, generic format:\n"; cout << " generic_string()-----: " << p.generic_string() << endl; wcout << L" generic_wstring()----: " << p.generic_wstring() << endl; cout << "\ndecomposition:\n"; cout << " root_name()----------: " << p.root_name() << '\n'; cout << " root_directory()-----: " << p.root_directory() << '\n'; cout << " root_path()----------: " << p.root_path() << '\n'; cout << " relative_path()------: " << p.relative_path() << '\n'; cout << " parent_path()--------: " << p.parent_path() << '\n'; cout << " filename()-----------: " << p.filename() << '\n'; cout << " stem()---------------: " << p.stem() << '\n'; cout << " extension()----------: " << p.extension() << '\n'; cout << "\nquery:\n"; cout << " empty()--------------: " << say_what(p.empty()) << '\n'; cout << " is_absolute()--------: " << say_what(p.is_absolute()) << '\n'; cout << " has_root_name()------: " << say_what(p.has_root_name()) << '\n'; cout << " has_root_directory()-: " << say_what(p.has_root_directory()) << '\n'; cout << " has_root_path()------: " << say_what(p.has_root_path()) << '\n'; cout << " has_relative_path()--: " << say_what(p.has_relative_path()) << '\n'; cout << " has_parent_path()----: " << say_what(p.has_parent_path()) << '\n'; cout << " has_filename()-------: " << say_what(p.has_filename()) << '\n'; cout << " has_stem()-----------: " << say_what(p.has_stem()) << '\n'; cout << " has_extension()------: " << say_what(p.has_extension()) << '\n'; return 0; } [ORIG_END] -->

Запустите приведенные ниже примеры в своей системе и попробуйте различные аргументы пути. Вот призыв, о котором мы поговорим подробно:

Ubuntu Linux
<
$ ./path_info /foo bar baa.txt
composed path:
  operator<<()---------: "/foo/bar/baa.txt"
  make_preferred()-----: "/foo/bar/baa.txt"
elements:
  "/"
  "foo"
  "bar"
  "baa.txt"
observers, native format:
  native()-------------: /foo/bar/baa.txt
  c_str()--------------: /foo/bar/baa.txt
  string()-------------: /foo/bar/baa.txt
  wstring()------------: /foo/bar/baa.txt
observers, generic format:
  generic_string()-----: /foo/bar/baa.txt
  generic_wstring()----: /foo/bar/baa.txt
decomposition:
  root_name()----------: ""
  root_directory()-----: "/"
  root_path()----------: "/"
  relative_path()------: "foo/bar/baa.txt"
  parent_path()--------: "/foo/bar"
  filename()-----------: "baa.txt"
  stem()---------------: "baa"
  extension()----------: ".txt"
query:
  empty()--------------: false
  is_absolute()--------: true
  has_root_name()------: false
  has_root_directory()-: true
  has_root_path()------: true
  has_relative_path()--: true
  has_parent_path()----: true
  has_filename()-------: true
  has_stem()-----------: true
  has_extension()------: true
>
 
Microsoft Windows
<
>path_info \foo bar baa.txt
composed path:
operator<<()---------: "\foo\bar\baa.txt"
make_preferred()-----: "\foo\bar\baa.txt"
elements:
  "/"
  "foo"
  "bar"
  "baa.txt"
observers, native format:
native()-------------: \foo\bar\baa.txt
c_str()--------------: \foo\bar\baa.txt
string()-------------: \foo\bar\baa.txt
wstring()------------: \foo\bar\baa.txt
observers, generic format:
generic_string()-----: /foo/bar/baa.txt
generic_wstring()----: /foo/bar/baa.txt
decomposition:
root_name()----------: ""
root_directory()-----: "\"
root_path()----------: "\"
relative_path()------: "foo\bar\baa.txt"
parent_path()--------: "\foo\bar"
filename()-----------: "baa.txt"
stem()---------------: "baa"
extension()----------: ".txt"
query:
empty()--------------: false
is_absolute()--------: false
has_root_name()------: false
has_root_directory()-: true
has_root_path()------: true
has_relative_path()--: true
has_parent_path()----: true
has_filename()-------: true
has_stem()-----------: true
has_extension()------: true
>

Мы подробно рассмотрим приведенный выше код, чтобы лучше понять, что происходит.

A common need is to compose a path from its constituent directories. Class path uses / and /= operators to append elements. That's a reminder that these operations append the operating system's preferred directory separator if needed. The preferred directory separator is a slash on POSIX-like systems, and a backslash on Windows-like systems.

That's what this code does before displaying the resulting path p using the class path stream inserter:

<
 path p;
  for (; argc > 1; --argc, ++argv)
    p /= argv[1];  // compose path p from the command line arguments
  cout  <<  "\ncomposed path:\n";
  cout  <<  "  operator<<()---------: " << p << "\n";
  cout  <<  "  make_preferred()-----: " << p.make_preferred() << "\n";
> path p; for (; argc > 1; --argc, ++argv) p /= argv[1]; // compose path p from the command line arguments cout << "\ncomposed path:\n"; cout << " operator<<()---------: " << p << "\n"; cout << " make_preferred()-----: " << p.make_preferred() << "\n"; [ORIG_END] -->

Одна абстракция для размышлений о пути — это последовательность элементов, где элементы являются именами каталогов и файлов. Чтобы поддержать эту абстракцию, класс<path>предоставляет итераторы, подобные STL, а также функции<begin()>и<end()>.

Вот код, который произвел список элементов в приведенном выше списке вывода:

<
cout << "\nelements:\n";
for (auto element : p)
  cout << " " << element << '\n';
>

Давайте посмотрим на функции наблюдателя классового пути:

<
 cout  <<  "\nobservers, native format:" << endl;
# ifdef BOOST_POSIX_API
  cout  <<  "  native()-------------: " << p.native() << endl;
  cout  <<  "  c_str()--------------: " << p.c_str() << endl;
# else  // BOOST_WINDOWS_API
  wcout << L"  native()-------------: " << p.native() << endl;
  wcout << L"  c_str()--------------: " << p.c_str() << endl;
# endif
  cout  <<  "  string()-------------: " << p.string() << endl;
  wcout << L"  wstring()------------: " << p.wstring() << endl;
  cout  <<  "\nobservers, generic format:\n";
  cout  <<  "  generic_string()-----: " << p.generic_string() << endl;
  wcout << L"  generic_wstring()----: " << p.generic_wstring() << endl;
> cout << "\nobservers, native format:" << endl; # ifdef BOOST_POSIX_API cout << " native()-------------: " << p.native() << endl; cout << " c_str()--------------: " << p.c_str() << endl; # else // BOOST_WINDOWS_API wcout << L" native()-------------: " << p.native() << endl; wcout << L" c_str()--------------: " << p.c_str() << endl; # endif cout << " string()-------------: " << p.string() << endl; wcout << L" wstring()------------: " << p.wstring() << endl; cout << "\nobservers, generic format:\n"; cout << " generic_string()-----: " << p.generic_string() << endl; wcout << L" generic_wstring()----: " << p.generic_wstring() << endl; [ORIG_END] -->

Нативные наблюдатели должны использоваться при взаимодействии с операционной системой или с пользователями.

Общий формат наблюдателей должен использоваться, когда результаты должны быть портативными и однородными независимо от операционной системы.

<path>объекты всегда держат имена путей в родном формате, но в противном случае оставляют их неизменными от своего источника. Функцияpreferred()преобразуется в предпочтительную форму, если нативный формат имеет несколько форм. Таким образом, в Windows он преобразует слэши в обратные.

Переходим к разложению:

<
 cout  <<  "\ndecomposition:\n";
  cout  <<  "  root_name()----------: " << p.root_name() << '\n';
  cout  <<  "  root_directory()-----: " << p.root_directory() << '\n';
  cout  <<  "  root_path()----------: " << p.root_path() << '\n';
  cout  <<  "  relative_path()------: " << p.relative_path() << '\n';
  cout  <<  "  parent_path()--------: " << p.parent_path() << '\n';
  cout  <<  "  filename()-----------: " << p.filename() << '\n';
  cout  <<  "  stem()---------------: " << p.stem() << '\n';
  cout  <<  "  extension()----------: " << p.extension() << '\n';
> cout << "\ndecomposition:\n"; cout << " root_name()----------: " << p.root_name() << '\n'; cout << " root_directory()-----: " << p.root_directory() << '\n'; cout << " root_path()----------: " << p.root_path() << '\n'; cout << " relative_path()------: " << p.relative_path() << '\n'; cout << " parent_path()--------: " << p.parent_path() << '\n'; cout << " filename()-----------: " << p.filename() << '\n'; cout << " stem()---------------: " << p.stem() << '\n'; cout << " extension()----------: " << p.extension() << '\n'; [ORIG_END] -->

 И, наконец, функции запроса:

<
 cout  <<  "\nquery:\n";
  cout  <<  "  empty()--------------: " << say_what(p.empty()) << '\n';
  cout  <<  "  is_absolute()--------: " << say_what(p.is_absolute()) << '\n';
  cout  <<  "  has_root_name()------: " << say_what(p.has_root_name()) << '\n';
  cout  <<  "  has_root_directory()-: " << say_what(p.has_root_directory()) << '\n';
  cout  <<  "  has_root_path()------: " << say_what(p.has_root_path()) << '\n';
  cout  <<  "  has_relative_path()--: " << say_what(p.has_relative_path()) << '\n';
  cout  <<  "  has_parent_path()----: " << say_what(p.has_parent_path()) << '\n';
  cout  <<  "  has_filename()-------: " << say_what(p.has_filename()) << '\n';
  cout  <<  "  has_stem()-----------: " << say_what(p.has_stem()) << '\n';
  cout  <<  "  has_extension()------: " << say_what(p.has_extension()) << '\n';
> cout << "\nquery:\n"; cout << " empty()--------------: " << say_what(p.empty()) << '\n'; cout << " is_absolute()--------: " << say_what(p.is_absolute()) << '\n'; cout << " has_root_name()------: " << say_what(p.has_root_name()) << '\n'; cout << " has_root_directory()-: " << say_what(p.has_root_directory()) << '\n'; cout << " has_root_path()------: " << say_what(p.has_root_path()) << '\n'; cout << " has_relative_path()--: " << say_what(p.has_relative_path()) << '\n'; cout << " has_parent_path()----: " << say_what(p.has_parent_path()) << '\n'; cout << " has_filename()-------: " << say_what(p.has_filename()) << '\n'; cout << " has_stem()-----------: " << say_what(p.has_stem()) << '\n'; cout << " has_extension()------: " << say_what(p.has_extension()) << '\n'; [ORIG_END] -->

Это довольно очевидно, но обратите внимание на разницу в результате<is_absolute()>между Linux и Windows. Поскольку не существует корневого имени (т.е. спецификатора диска или сетевого имени), одиночный слэш (или обратный слэш) является относительным путем в Windows, но абсолютным путем в POSIX-подобных операционных системах.

Error reporting

Функция Boost.Filesystem<file_size>, как и многие операционные функции, имеет две перегрузки:

uintmax_t file_size(const path& p);
uintmax_t file_size(const path& p, system::error_code& ec);

Единственное существенное различие между ними заключается в том, как они сообщают об ошибках.

Первая подпись будет содержать исключения для сообщения об ошибках. Исключение< filesystem_error>будет сделано из-за оперативной ошибки.<filesystem_error>происходит от<std::runtime_error>. Он имеет функцию участника для получения< error_code>, сообщенного источником ошибки. Он также имеет функции-члены для получения пути или путей, которые вызвали ошибку.

Мотивация для второй подписи:Выбрасывание исключений из ошибок было всей историей сообщений об ошибках для самых ранних версий Boost. Файловая система, и даже исключение ошибок, работает очень хорошо для многих приложений. Но отчеты пользователей просочились в то, что некоторый код стал настолько усеян попытками поймать блоки, чтобы быть нечитаемым и неподъемным. В некоторых приложениях ошибки ввода/вывода не являются исключительными, и это пример использования второй подписи.

Функции с аргументом<system::error_code&>устанавливают этот аргумент для сообщения о состоянии операционной ошибки, и поэтому не делайте исключений при возникновении ошибок, связанных с вводом/выводом. Полное объяснение см.Сообщение об ошибкев справочной документации.


Авторское право Beman Dawes 2010, 2015

Распространяется в соответствии с Лицензией на программное обеспечение Boost, версия 1.0. См.www.boost.org/LICENSE_1_0.txt

Пересмотрено26 июля 201526 July 2015[ORIG_END] -->

Статья Filesystem Tutorial раздела может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 21:33:39/0.013401031494141/0