Читать книги » Книги » Компьютеры и Интернет » Программирование » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Читать книгу C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц, Яцек Галовиц . Жанр: Программирование.
C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Название: C++17 STL Стандартная библиотека шаблонов
Дата добавления: 15 июль 2023
Количество просмотров: 1 470
(18+) Внимание! Книга может содержать контент только для совершеннолетних. Для несовершеннолетних просмотр данного контента СТРОГО ЗАПРЕЩЕН! Если в книге присутствует наличие пропаганды ЛГБТ и другого, запрещенного контента - просьба написать на почту для удаления материала.
Читать онлайн

C++17 STL Стандартная библиотека шаблонов читать книгу онлайн

C++17 STL Стандартная библиотека шаблонов - читать онлайн , автор Яцек Галовиц

С++ — объектно-ориентированный язык программирования, без которого сегодня немыслима промышленная разработка ПО. В этой замечательной книге описана работа с контейнерами, алгоритмами, вспомогательными классами, лямбда-выражениями и другими интересными инструментами, которыми богат современный С++. Освоив материал, вы сможете коренным образом пересмотреть привычный подход к программированию.
Преимущество издания — в подробном описании стандартной библиотеки шаблонов С++, STL. Ее свежая версия была выпущена в 2017 году. В книге вы найдете более 90 максимально реалистичных примеров, которые демонстрируют всю мощь STL. Многие из них станут базовыми кирпичиками для решения более универсальных задач.
Вооружившись этой книгой, вы сможете эффективно использовать С++17 для создания высококачественного и высокопроизводительного ПО, применимого в различных отраслях.

Перейти на страницу:
class="code">        [](size_t accum, const directory_entry &e) {

    return accum + entry_size(e);

  });

}

4. Для повышения читабельности воспользуемся функцией size_string, которая уже встречалась в этой главе. Она просто сокращает большие размеры файлов, делая их «аккуратнее» и добавляя префиксы «кило», «мега» или «гига»:

static string size_string(size_t size)

{

  stringstream ss;

  if        (size >= 1000000000) {

    ss <<   (size / 1000000000) << 'G';

  } else if (size >= 1000000) {

    ss <<   (size / 1000000) << 'M';

  } else if (size >= 1000) {

    ss <<   (size / 1000) << 'K';

  } else { ss << size << 'B'; }

  return ss.str();

}

5. Первое, что нужно сделать в функции main, — проверить, предоставил ли пользователь путь к файлу в командной строке. Если это не так, то возьмем текущий каталог. Прежде чем продолжить, проверим, существует ли данный каталог:

int main(int argc, char *argv[])

{

  path dir {argc > 1 ? argv[1] : "."};

  if (!exists(dir)) {

    cout << "Path " << dir << " does not exist.n";

    return 1;

}

6. Теперь можно проитерировать по всем записям каталога и вывести на экран их имена и размер:

  for (const auto &entry : directory_iterator{dir}) {

    cout << setw(5) << right

         << size_string(entry_size(entry))

         << " " << entry.path().filename().c_str()

         << 'n';

  }

}

7. Компиляция и запуск программы дадут следующий результат. Я запустил ее для каталога, в котором находится офлайн-справка по С++. Поскольку он содержит и подкаталоги, наша вспомогательная функция, суммирующая размер файла, очень пригодится:

$ ./file_size ~/Documents/cpp_reference/en/

 19M c

 12K c.html

147M cpp

 17K cpp.html 22K index.html

 22K Main_Page.html

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

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

Единственное, что мы сделали для определения того, можем ли вызвать непосредственно file_size или нужно рекурсивно спуститься дальше, — реализовали предикат is_directory. Он работает для каталогов, которые содержат только обычные файлы и каталоги.

Поскольку наша программа довольно проста, она даст сбой при следующих условиях.

□ Функция file_size работает только для обычных файлов и символьных ссылок. Она генерирует исключение во всех других случаях.

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

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

Подбиваем статистику о типах файлов

В предыдущем примере мы реализовали инструмент, который выводит на экран размер всех членов каталога.

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

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

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

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

#include <iostream>

#include <sstream>

#include <iomanip>

#include <map>

#include <filesystem>

using namespace std;

using namespace filesystem;

2. Функция size_string была полезна в предыдущих примерах. Она преобразует размеры файлов в читабельные строки:

static string size_string(size_t size)

{

  stringstream ss;

  if (size >= 1000000000) {

    ss <<   (size / 1000000000) << 'G';

  } else if (size >= 1000000) {

    ss <<   (size / 1000000) << 'M';

  } else if (size >= 1000) {

    ss <<   (size / 1000) << 'K';

  } else { ss << size << 'B'; }

return ss.str();

}

3. Затем реализуем вспомогательную функцию, которая принимает объект пути и итерирует по всем файлам данного пути. При этом она собирает всю информацию в ассоциативный массив, в котором соотносятся расширения файлов и пары, содержащие общее количество файлов и их суммарный размер.

static map<string, pair<size_t, size_t>> ext_stats(const path &dir)

{

  map<string, pair<size_t, size_t>> m;

  for (const auto &entry :

      recursive_directory_iterator{dir}) {

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

    const path p {entry.path()};

    const file_status fs {status(p)};

    if (is_directory(fs)) { continue; }

5. Далее извлекаем расширения из строки, представляющей запись каталога. Если у нее нет расширения, то просто опускаем ее:

    const string ext {p.extension().string()};

    if (ext.length() == 0) { continue; }

6. Подсчитаем размер текущего файла. Затем найдем агрегатный объект в ассоциативном массиве для этого расширения. Если такого объекта нет, то неявно создадим его. Просто увеличим счетчик количества файлов и добавим размер файла в переменную-аккумулятор:

    const size_t size {file_size(p)};

    auto &[size_accum, count] = m[ext];

    size_accum += size;

    count      += 1;

  }

7. После этого вернем ассоциативный массив:

  return m;

}

8. В функции main примем путь, предоставленный пользователем в командной строке. Конечно, нужно проверить, существует ли он, поскольку в противном случае продолжать не имеет смысла.

int main(int argc, char *argv[])

{

  path dir {argc > 1 ? argv[1] : "."};

  if (!exists(dir)) {

    cout << "Path " << dir << " does not exist.n";

    return 1;

  }

9. Можно мгновенно проитерировать

Перейти на страницу:
Комментарии (0)