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

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

Книгу C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц читаем онлайн бесплатно полную версию! Чтобы начать читать не надо регистрации. Напомним, что читать онлайн вы можете не только на компьютере, но и на андроид (Android), iPhone и iPad. Приятного чтения!

1 ... 112 113 114 115 116 117 118 119 120 121
Перейти на страницу:

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
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. Можно мгновенно проитерировать

1 ... 112 113 114 115 116 117 118 119 120 121
Перейти на страницу:
Отзывы - 0

Прочитали книгу? Предлагаем вам поделится своим отзывом от прочитанного(прослушанного)! Ваш отзыв будет полезен читателям, которые еще только собираются познакомиться с произведением.


Уважаемые читатели, слушатели и просто посетители нашей библиотеки! Просим Вас придерживаться определенных правил при комментировании литературных произведений.

  • 1. Просьба отказаться от дискриминационных высказываний. Мы защищаем право наших читателей свободно выражать свою точку зрения. Вместе с тем мы не терпим агрессии. На сайте запрещено оставлять комментарий, который содержит унизительные высказывания или призывы к насилию по отношению к отдельным лицам или группам людей на основании их расы, этнического происхождения, вероисповедания, недееспособности, пола, возраста, статуса ветерана, касты или сексуальной ориентации.
  • 2. Просьба отказаться от оскорблений, угроз и запугиваний.
  • 3. Просьба отказаться от нецензурной лексики.
  • 4. Просьба вести себя максимально корректно как по отношению к авторам, так и по отношению к другим читателям и их комментариям.

Надеемся на Ваше понимание и благоразумие. С уважением, администратор knigkindom.ru.


Партнер

Новые отзывы

  1. Р.Д.У. Р.Д.У.22 август 02:17 ...мне тоже понравился этот русский вестерн. И озвучено неплохо. Советую.... Силантьев Вадим – Засада
  2. Гость Любовь Гость Любовь21 август 20:01 Прочитала залпом.... интересный сюжет, история захватывает, плакала вместе с героями. спасибо автору за интересное... Вернуть жену. Без права на прощение? - Ира Орлова
  3. Ма Ма21 август 02:06 Роман хороший, но очень топорный и поэтому скучноватый, все как будто поверхностно, акцент на работе героев - киллер и главбух, а... Гектор - Ольга Дашкова
Все комметарии
Новое в блоге