В строке 60 каталог открывается для чтения (второй аргумент равен 0, что означает
O_RDONLY
). В строке 65 читается
struct direct
. В строке 66 проверяется, не является ли элемент каталога пустым, т. е. с номером индекса 0. Строки 67 и 68 проверяют на наличие '
.
' и '
..
'. По достижении строки 69 мы знаем, что было встречено какое-то другое имя файла, следовательно, этот каталог не пустой.
(Тест '
!strcmp(s1, s2)
'
является более короткой формой '
strcmp(s1, s2) == 0
', т.е. проверкой совпадения строк. Стоит заметить, что мы рассматриваем '
!strcmp(s1, s2)
' как плохой стиль. Как сказал однажды Генри Спенсер (Henry Spencer), «
strcmp
это не boolean!».)
Когда 4.2 BSD представило новый формат файловой системы, который допускал длинные имена файлов и обеспечивал лучшую производительность, были также представлены несколько новых функций для абстрагирования чтения каталогов. Этот набор функций можно использовать независимо от того, какова лежащая в основе файловая система и как организованы каталоги. Основная ее часть стандартизована POSIX, а программы, использующие ее, переносимы между системами GNU/Linux и Unix.
5.3.1. Базовое чтение каталогов
Элементы каталогов представлены
struct dirent
(не то же самое, что V7
struct direct
!):
struct dirent {
...
ino_t d_ino; /* расширение XSI --- см. текст */
char d_name[...]; /* О размере этого массива см. в тексте */
...
};
Для переносимости POSIX указывает лишь поле
d_name
, которое является завершающимся нулем массивом байтов, представляющим часть элемента каталога с именем файла. Размер
d_name
стандартом не указывается, кроме того, что там перед завершающим нулем может быть не более
NAME_MAX
байтов. (
NAME_MAX
определен в
<limits.h>
.) Расширение XSI POSIX предусматривает поле номера индекса
d_ino
.
На практике, поскольку имена файлов могут быть различной длины, a
NAME_MAX
обычно довольно велико (подобно 255),
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
возвращает
NULL
, именованный каталог не может быть открыт для чтения, а errno содержит
код ошибки.
Открыв переменную
DIR*
, можно использовать ее для получения указателя на
struct dirent
, представляющего следующий элемент каталога.
readdir
возвращает
NULL
, если достигнут конец каталога [54] или произошла ошибка.
Наконец,
closedir
является аналогичной функции
fclose
в
<stdio.h>
; она закрывает открытую переменную
DIR*
. Чтобы начать с начала каталога, можно использовать функцию
rewinddir
.
54
То есть прочитаны все элементы каталога — Примеч. науч. ред.
Имея в распоряжении (или по крайней мере в библиотеке С) эти функции, мы можем написать небольшую программу
catdir
, которая «отображает» содержимое каталога. Такая программа представлена в