При достижении конца каталога или при ошибке функция readdir() возвращает NULL; в последнем случае для указания на ошибку присваивается значение переменной errno. Для различения этих двух случаев можно написать такой код:
errno = 0;
direntp = readdir(dirp);
if (direntp == NULL) {
if (errno!= 0) {
/* Обработка ошибки */
} else {
/* Достижение конца каталога */
}
}
Если содержимое каталога меняется, пока программа сканирует его с помощью функции readdir(), то эта программа может не заметить изменений. Стандарт SUSv3 явным образом отмечает, что возникает неопределенность: возвратит ли функция readdir() имя файла, который был добавлен в данный каталог или был удален из него за время, прошедшее с момента последнего вызова функции opendir() или rewinddir()? Все имена файлов, которые не были добавлены или удалены с момента последнего вызова, гарантированно возвращаются.
Функция rewinddir() перемещает поток каталога обратно к началу, чтобы следующий вызов функции readdir() начинал работу с первого файла в данном каталоге.
#include
void rewinddir(DIR *
Функция closedir() закрывает открытый поток каталога, на который указывает аргумент dirp, высвобождая ресурсы, использованные этим потоком.
#include
int closedir(DIR *
Возвращает 0 при успешном завершении или –1 при ошибке
Следующие две функции, telldir() и seekdir(), которые также определены в стандарте SUSv3, разрешают произвольный доступ внутри потока каталога. Дополнительную информацию об этих функциях см. на страницах руководства.
Поток каталога обладает связанным с ним файловым дескриптором. Функция dirfd() возвращает дескриптор, относящийся к потоку каталога, на который указывает аргумент dirp.
#include
int dirfd(DIR *
Возвращает файловый дескриптор при успешном завершении или –1 при ошибке
Можно было бы, например, передать файловый дескриптор, возвращенный функцией dirfd(), функции fchdir() (см. раздел 18.10), чтобы изменить текущий рабочий каталог процесса на соответствующий. В другом варианте можно было бы передать файловый дескриптор как аргумент dirfd в одной из функций, описанных в разделе 18.11.
Функция dirfd() появляется также в версиях BSD, однако присутствует в немногих других реализациях. Она не определена в стандарте SUSv3, но описана в стандарте SUSv4.
Здесь уместно отметить: функция opendir() автоматически устанавливает флаг close-on-exec (FD_CLOEXEC) для файлового дескриптора, связанного с потоком каталога. Это дает гарантию того, что данный файловый дескриптор будет автоматически закрыт после выполнения вызова exec(). (Стандарт SUSv3 требует такого поведения.) Мы рассмотрим флаг close-on-exec в разделе 27.4.
В листинге 18.2 применены функции opendir(), readdir() и closedir() для вывода содержимого каталогов, указанных в командной строке (или в рабочем каталоге, если аргументы не указаны). Ниже приведен пример использования этой программы:
$ mkdir sub
$ touch sub/a sub/b
$ ./list_files sub
sub/a
sub/b
Листинг 18.2. Сканирование каталога
dirs_links/list_files.c
#include
#include "tlpi_hdr.h"
static void /* Перечисляет все файлы в каталоге 'dirPath' */
listFiles(const char *dirpath)
{
DIR *dirp;
struct dirent *dp;
Boolean isCurrent; /* Истина, если 'dirpath' равен"." */
isCurrent = strcmp(dirpath, ".") == 0;
dirp = opendir(dirpath);
if (dirp == NULL) {
errMsg("opendir failed on '%s'", dirpath);
return;
}
/* Для каждой записи в этом каталоге выводим имя каталога + имя файла */
for (;;) {
errno = 0; /* Чтобы отличить ошибку от достижения конца папки */
dp = readdir(dirp);
if (dp == NULL)
break;
if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
continue; /* Пропускаем. и… */
if (!isCurrent)
printf("%s/", dirpath);
printf("%s\n", dp->d_name);
}
if (errno!= 0)
errExit("readdir");
if (closedir(dirp) == -1)
errMsg("closedir");
}
int
main(int argc, char *argv[])
{
if (argc > 1 && strcmp(argv[1], "-help") == 0)
usageErr("%s [dir-path…]\n", argv[0]);
if (argc == 1) /* Аргументов нет — используем текущий каталог */
listFiles(".");
else
for (argv++; *argv; argv++)
listFiles(*argv);
exit(EXIT_SUCCESS);
}
dirs_links/list_files.c
Функция readdir_r() является вариантом функции readdir(). Ключевым семантическим различием между этими функциями является то, что первая допускает многократный ввод, а вторая — нет. Это связано вот с чем: функция readdir_r() возвращает запись файла через аргумент entry, назначаемый вызывающим процессом, а функция readdir() возвращает информацию, задействуя указатель на статически выделенную структуру. Мы рассмотрим многократный ввод в подразделе 21.1.2 и разделе 31.1.
#include