Linux программирование в примерах
38 DIR *dp;39 struct dirent *ent;4041 if ((dp = opendir(dir)) == NULL) {42 fprintf(stderr, "%s: %s: cannot open for reading: %s\n",43 myname, dir, strerror(errno));44 return 1;45 }4647 errno = 0;48 while ((ent = readdir(dp)) != NULL)49 printf("%8ld %s\n", ent->d_ino, ent->d_name);5051 if (errno != 0) {52 fprintf(stderr, "%s: %s: reading directory entries: %s\n",53 myname, dir, strerror(errno));54 return 1;55 }5657 if (closedir(dp) != 0) {58 fprintf(stderr, "%s: %s: closedir: %s\n",59 myname, dir, strerror(errno));60 return 1;61 }6263 return 0;64 }Функция
делает всю работу и большую часть кода проверки ошибок. Основой функции являются строки 48 и 49:process()while ((ent = readdir(dp)) != NULL)printf("%8ld %s\n", ent->d_ino, ent->d_name);Этот цикл читает элементы каталога, по одной за раз, до тех пор, пока
не возвратитreaddir(). Тело цикла отображает для каждого элемента номер индекса и имя файла. Вот что происходит при запуске программы:NULL$ <b>ch05-catdir</b> /* По умолчанию текущий каталог */639063 .639062 ..639064 proposal.txt639012 lightsabers.url688470 code638976 progex.texi639305 texinfo.tex639007 15-processes.texi639011 00-preface.texi639020 18-tty.texi638980 Makefile639239 19-i18n.texi...Вывод никаким образом не сортируется; он представляет линейное содержимое каталога. (Как сортировать содержимое каталога мы опишем в разделе 6.2 «Функции сортировки и поиска»).
5.3.1.1. Анализ переносимости
Есть несколько соображений по переносимости. Во-первых, не следует предполагать, что двумя первыми элементами, возвращаемыми
, всегда будут 'readdir()' и '.'. Многие файловые системы используют организацию каталогов, которые отличаются от первоначального дизайна Unix, и '..' и '.' могут быть в середине каталога или даже вовсе не присутствовать [55]...Во-вторых, стандарт POSIX ничего не говорит о возможных значениях
. Он говорит, что возвращенные структуры представляют элементы каталогов для файлов; это предполагает, чтоd_infoне возвращает пустые элементы, поэтому реализация GNU/Linuxreaddir()не беспокоится с возвратом элементов, когда 'readdir()'; она переходит к следующему действительному элементу.d_ino == 0Поэтому по крайней мере на системах GNU/Linux и Unix маловероятно, что
когда-нибудь будет равен нулю. Однако, лучше по возможности вообще избегать использования этого поля.d_inoНаконец, некоторые системы используют
вместоd_filenoвd_ino. Знайте об этом, когда нужно перенести на такие системы код, читающий каталоги.struct direntКосвенные системные вызовы«Не пробуйте это дома, дети!»
- М-р Wizard -
Многие системные вызовы, такие, как
,open()иread(), предназначены для вызова непосредственно из кода пользователя: другими словами, из кода, который пишете вы как разработчик GNU/Linux.write()Однако, другие системные вызовы существуют лишь для того, чтобы дать возможность реализовать стандартные библиотечные функции более высокого уровня, и никогда не должны вызываться непосредственно. Одним из таких системных вызовов является GNU/Linux
; он читает несколько элементов каталога в буфер, предоставленный вызывающим — в данном случае, кодом реализацииgetdents(). Затем кодreaddir()возвращает действительные элементы каталога, по одному за раз, пополняя при необходимости буфер.readdir()Эти системные вызовы только-для-библиотечного-использования можно отличить от вызовов для-использования-пользователем по их представлению в странице справки. Например, из getdents(2).
ИМЯgetdents - получить элементы каталогаОПИСАНИЕ#include <unistd.h>#include <linux/types.h>#include <linux/dirent.h>#include <linux/unistd.h>_syscall3(int, getdents, uint, fd, struct dirent*,dirp, uint, count);int getdents(unsigned int fd, struct dirent *dirp,unsigned int count);Любой системный вызов, использующий макрос
, не должен вызываться кодом приложения. (Дополнительную информацию об этих вызовах можно найти в справочной странице для intro(2); вам следует прочесть эту справочную страницу, если вы этого еще не сделали.)_syscallX()В случае
на многих других системах Unix есть сходный системный вызов; иногда с тем же именем, иногда с другим. Поэтому попытка использования этих вызовов привела бы в любом случае лишь к большому беспорядку с переносимостью; гораздо лучше во всех случаях использоватьgetdents(), интерфейс которого хорошо определен, стандартизован и переносим.readdir()