Опубликован: 15.06.2004 | Уровень: специалист | Доступ: платный
Лекция 6:

Средства обработки структурированных данных

Средства обработки каталогов

Обработка каталогов, как и обычных файлов, начинается с их открытия. Для этого предназначена функция opendir() (см. листинг 6.50).

#include <dirent.h>
DIR *opendir (const char *dirname);
Листинг 6.50. Описание функции opendir().

После открытия текущим становится первый элемент каталога. Если в дальнейшем понадобится вновь позиционироваться на первый элемент, можно воспользоваться функцией rewinddir() (см. листинг 6.51).

#include <dirent.h>
void rewinddir (DIR *dirp);
Листинг 6.51. Описание функции rewinddir().

Чтение элементов каталога выполняет функция readdir() (см. листинг 6.52), которая возвращает указатель на структуру, представляющую текущий элемент каталога ; после ее завершения текущим становится следующий элемент достижении конца каталога и в случае ошибки возвращается пустой указатель. Следовательно, если приложению необходимо различать обе ситуации, оно должно обнулить значение переменной   errno перед вызовом readdir(), а затем, если результат равен NULL, проанализировать это значение.

#include <dirent.h>
struct dirent *readdir (DIR *dirp);
Листинг 6.52. Описание функции readdir().

Согласно стандарту POSIX-2001, структура dirent содержит по крайней мере одно поле:

char d_name []; /* Имя файла */

В качестве необязательного описано еще одно поле:

ino_t d_ino; /* Порядковый номер файла */

Если элемент каталога представляет символьную ссылку, значение этого поля не определено.

Следует учитывать, что указатель, возвращаемый функцией readdir(), может ссылаться на область памяти, перезаписываемую другими обращениями к readdir() с тем же значением аргумента dirp. Кроме того, нужно помнить и о том, что содержимое читаемого каталога асинхронно изменяют другие процессы (потоки управления), создающие и удаляющие файлы.

После завершения работы с каталогом его следует закрыть с помощью функции closedir() (см. листинг 6.53), возвращающей

#include <dirent.h>
int closedir (DIR *dirp);
Листинг 6.53. Описание функции closedir().

Нередко чтение элементов каталога и сопоставление с шаблоном имен файлов сочетаются (см. выше раздел "Генерация маршрутных имен файлов" ). Подобное сопоставление реализует функция fnmatch() (см. листинг 6.54).

#include <fnmatch.h>
int fnmatch (const char *file_pattern, 
   const char *file_name, int flags);
Листинг 6.54. Описание функции fnmatch().

На процесс сопоставления имени file_name с шаблоном   file_pattern влияют следующие флаги:

FNM_PATHNAME

Трактовать имя file_name как маршрутное. Символу / в имени должен явным образом сопоставляться этот же символ в шаблоне (а не *, ? или выражение в квадратных скобках). Если флаг не установлен, символ / трактуется наравне с другими.

FNM_NOESCAPE

При наличии этого флага символ \ трактуется наравне с другими. В противном случае он играет экранирующую роль.

FNM_PERIOD

Если этот флаг установлен, точка в начале имени файла должна сопоставляться с точкой в шаблоне. Иначе точка в начале имени сопоставляется на общих основаниях.

В случае успешного сопоставления функция fnmatch() возвращает ноль, при неудаче результат равен FNM_NOMATCH, в случае ошибки возвращается другое ненулевое значение.

В качестве примера употребления описанных функций рассмотрим программу, которая выводит имена файлов текущего каталога, удовлетворяющие заданным в командной строке шаблонам (см. листинг 6.55).

#include <dirent.h>
#include <fnmatch.h>
#include <errno.h>
#include <stdio.h>

/* Программа сопоставляет имена файлов текущего каталога с заданными шаблонами */

#define SEARCH_DIR "."

static void match_names (DIR *dirp, const char *pattern) {
   struct dirent *dp;

   rewinddir (dirp);

   while (errno = 0, (dp = readdir (dirp)) != NULL) {
      if (fnmatch (pattern, dp->d_name, FNM_PERIOD) == 0) {
        (void) printf (" %s\n", dp->d_name);
      }
   }

   if (errno != 0) {
       perror ("Ошибка при чтении каталога " SEARCH_DIR);
   }
}

int main (int argc, char *argv []) {
   DIR *dirp;
   int i;

   if ((dirp = opendir (SEARCH_DIR)) == NULL) {
      perror ("Ошибка при открытии каталога " SEARCH_DIR);
      return (-1);
   }

   for (i = 1; i < argc; i++) {
     (void) printf ("Файлы каталога " SEARCH_DIR ", удовлетворяющие шаблону %s\n", argv [i]);
     match_names (dirp, argv [i]);
   }

   return (closedir (dirp));
}
Листинг 6.55. Пример использования функций, обрабатывающих каталоги.
Антон Коновалов
Антон Коновалов

В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13
Планируется ли актуализация материалов данного очень полезного курса?