Чтение онлайн

ЖАНРЫ

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:
Смотри также

Рецепт 10.12.

10.12. Чтение содержимого каталога

Проблема

Требуется прочитать содержимое каталога, вероятно, для того, чтобы сделать что-то с каждым его файлом или подкаталогом.

Решение

Для получения переносимого решения воспользуйтесь классами и функциями библиотеки Boost Filesystem. Она содержит ряд удобных функций по работе с файлами, обеспечивая переносимое представление путей, итераторы каталога и различные функции по переименованию, удалению и копированию файлов и т.п. Пример 10.19 показывает, как можно использовать некоторые из этих

средств.

Пример 10.19. Чтение каталога

#include <iostream>

#include <boost/filesystem/operations.hpp>

#include <boost/filesystem/fstream.hpp>

using namespace boost::filesystem;

int main(int argc, char** argv) {

 if (argc < 2) {

std::cerr << "Usage: " << argv[0] << " [dir name]\n";

return(EXIT_FAILURE);

 }

 path fullPath = // Создать полный, абсолютный путь

system_complete(path(argv[1], native));

 if (!exists(fullPath)) {

std::cerr << "Error: the directory " << fullPath.string

<< " does not exist.\n";

return(EXIT_FAILURE);

 }

 if (!is_directory(fullPath)) {

std::cout << fullPath.string << " is not a directory!\n";

return(EXIT_SUCCESS);

 }

 directory_iterator end;

 for (directory_iterator it(fullPath);

it != end; ++it) { // Просматривать в цикле каждый

// элемент каталога почти

std::cout << it->leaf; // так же, как это делалось бы для

if (is_directory(*it)) // STL-контейнера

std::cout << " (dir)";

std::cout << '\n';

 }

 return(EXIT_SUCCESS);

}

Обсуждение

Как и при создании и удалении каталогов (см. рецепты 10.10 и 10.11), не существует стандартного, переносимого способа чтения содержимого каталога. Чтобы облегчить жизнь в C++, библиотека Filesystem проекта Boost содержит ряд переносимых функций по работе с файлами и каталогами. Она также содержит много других функций; дополнительную информацию вы найдете при описании других рецептов этой главы или на веб-странице библиотеки Boost Filesystem сайта www.boost.com.

В примере 10.19 приводится простая программа просмотра каталога (наподобие команды

ls
в Unix или
dir
в MS-DOS). Сначала она следующим образом формирует абсолютный путь на основе аргументов, переданных программе.

path fullPath = complete(path(argv[1], native));

Тип данных переменной, содержащей путь, называется, естественно,

path
(путь). С этим типом данных работает файловая система, и он легко преобразуется в строку путем вызова
path::string
. После формирования пути программа проверяет его существование (с помощью
функции
exists
), затем с помощью другой функции,
is_directory
, проверяет, задает ли данный путь каталог. Если ответ положителен, то все хорошо и можно перейти к реальной работе по просмотру содержимого каталога.

Файловая система имеет класс с именем

directory_iterator
, который использует стандартную семантику итераторов, подобную применяемой для стандартных контейнеров, чтобы можно было использовать итераторы как указатели на элементы каталога. Однако в отличие от стандартных контейнеров здесь нет функции-члена
end
, представляющей элемент, следующий за последним элементом (т.е.
vector<T>::end
). Вместо этого, если вы создаете итератор каталога
directory_iterator
при помощи стандартного конструктора, он предоставляет конечный маркер, который вы можете использовать в операциях сравнения для определения момента завершения просмотра каталога. Поэтому используйте следующий оператор.

directory_iterator end;

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

for (directory_iterator it(fullPath); it != end; ++it) {

 // выполнить любые действия с *it

 std::cout << it->leaf;

}

Функция-член

leaf
возвращает строку, представляющую конечный элемент пути, а не весь путь, который вы можете получить, вызывая функцию-член
string
.

Если вам требуется обеспечить переносимость, но по каким-то причинам вы не можете использовать библиотеки Boost, обратите внимание на исходный код Boost. Он содержит операторы

#ifdef
, которые учитывают (по большей части) отличия среды Windows и ОС, использующих интерфейс Posix, и в частности отличия в представлении путей, например буквы дисководов и имена устройств.

Смотри также

Рецепты 10.10 и 10.11.

10.13. Извлечение расширения файла из строки

Проблема

Имеется имя файла или полный путь и требуется получить расширение файла, которое является частью имени файла, расположенной за последней точкой. Например, в именах файлов src.cpp, Window.class и Resume.doc расширениями файла являются соответственно .cpp, .class и .doc.

Решение

Преобразуйте имя файла или путь к нему в строку

string
, используйте функцию-член
rfind
для определения позиции последней точки и возвратите то, что находится за ней. Пример 10.20 показывает, как это можно сделать.

Пример 10.20. Получение расширения файла из его имени

#include <iostream>

#include <string>

using std::string;

string getFileExt(const string& s) {

 size_t i = s.rfind('.', s.length);

 if (i ! = string::npos) {

return(s.substr(i+1, s.length - i));

 }

 return("");

Поделиться с друзьями: