Linux программирование в примерах
(Тест '
' является более короткой формой '!strcmp(s1, s2)', т.е. проверкой совпадения строк. Стоит заметить, что мы рассматриваем 'strcmp(s1, s2) == 0' как плохой стиль. Как сказал однажды Генри Спенсер (Henry Spencer), «!strcmp(s1, s2)это не boolean!».)strcmp()Когда 4.2 BSD представило новый формат файловой системы, который допускал длинные имена файлов и обеспечивал лучшую производительность, были также представлены несколько новых функций для абстрагирования чтения каталогов. Этот набор функций можно использовать независимо от того, какова лежащая в основе файловая система и как организованы каталоги. Основная ее часть стандартизована POSIX, а программы, использующие ее, переносимы между системами GNU/Linux и Unix.
5.3.1. Базовое чтение каталогов
Элементы каталогов представлены
(не то же самое, что V7struct dirent!):struct directstruct dirent {...ino_t d_ino; /* расширение XSI --- см. текст */char d_name[...]; /* О размере этого массива см. в тексте */...};Для переносимости POSIX указывает лишь поле
, которое является завершающимся нулем массивом байтов, представляющим часть элемента каталога с именем файла. Размерd_nameстандартом не указывается, кроме того, что там перед завершающим нулем может быть не болееd_nameбайтов. (NAME_MAXопределен вNAME_MAX.) Расширение XSI POSIX предусматривает поле номера индекса<limits.h>.d_inoНа практике, поскольку имена файлов могут быть различной длины, a
обычно довольно велико (подобно 255),NAME_MAXсодержит дополнительные члены, которые помогают вести на диске учет элементов каталогов с переменными длинами. Эти дополнительные члены не существенны для обычного кода.struct direntСледующие функции предоставляют интерфейс чтения каталогов:
#include <sys/types.h> /* POSIX */#include <dirent.h>DIR *opendir(const char *name); /* Открыть каталог для чтения */struct dirent *readdir(DIR *dir); /* Вернуть struct dirent за раз */int closedir(DIR *dir); /* Закрыть открытый каталог */void rewinddir(DIR *dirp); /* Вернуться в начало каталога */Тип
является аналогом типаDIRвFILE. Это непрозрачный тип, что означает, что код приложения не должен знать, что находится внутри него; его содержимое предназначено для использования другими процедурами каталогов. Если<stdio.h>возвращаетopendir(), именованный каталог не может быть открыт для чтения, а errno содержит код ошибки.NULLОткрыв переменную
, можно использовать ее для получения указателя наDIR*, представляющего следующий элемент каталога.struct direntвозвращаетreaddir(), если достигнут конец каталога [54] или произошла ошибка.NULLНаконец,
является аналогичной функцииclosedir()вfclose(); она закрывает открытую переменную<stdio.h>. Чтобы начать с начала каталога, можно использовать функциюDIR*.rewinddir()Имея в распоряжении (или по крайней мере в библиотеке С) эти функции, мы можем написать небольшую программу
, которая «отображает» содержимое каталога. Такая программа представлена вcatdir:ch05-catdir.с1 /* ch05-catdir.с - Демонстрация opendir(), readdir(), closedir(). */23 #include <stdio.h> /* для printf() и т.д. */4 #include <errno.h> /* для errno */5 #include <sys/types.h> /* для системных типов */6 #include <dirent.h> /* для функций каталога */78 char *myname;9 int process(char *dir);1011 /* main --- перечисление аргументов каталога */1213 int main(int argc, char **argv)14 {15 int i;16 int errs = 0;1718 myname = argv[0];1920 if (argc == 1)21 errs = process("."); /* по умолчанию текущий каталог */22 else23 for (i = 1; i < argc; i++)24 errs += process(argv[i]);2526 return (errs != 0);27 }Эта программа вполне подобна
(см. раздел 4.2 «Представление базовой структуры программы»); функцияch04-cat.cпочти идентична. Главное различие в том, что по умолчанию используется текущий каталог, если нет аргументов (строки 20–21).main()29 /*30 * process --- сделать что-то с каталогом, в данном случае,31 * вывести пары индекс/имя в стандартный вывод.32 * Возвращает 0, если все OK, иначе 1.33 */3435 int36 process(char *dir)37 {