#include
DIR * opendir(const char * pathname);
int closedir(DIR * dir);
Системный вызов opendir()
возвращает указатель на тип данных DIR
, который является абстрактным (как и структура stdio
по имени FILE
) и которым не следует манипулировать вне библиотеки С. Поскольку каталоги можно открывать только для чтения, нет необходимости определять, в каком режиме открывается каталог, opendir()
срабатывает только в случае существования каталога — этот вызов нельзя использовать для создания новых каталогов (для этого служит mkdir()
). Закрытие каталога может не сработать только в случае некорректного значения аргумента dir
.
После открытия каталога его элементы читаются последовательно до конца каталога.
Системный вызов readdir()
возвращает имя следующего файла в каталоге. Каталоги не упорядочены каким-либо образом, поэтому не стоит предполагать, что оглавление каталога отсортировано. Если необходим упорядоченный список файлов, сортировку придется выполнять самостоятельно. Функция readdir()
определяется, как показано ниже.
#include
struct dirent * readdir (DIR * dir);
Вызывающему коду возвращается указатель на структуру struct dirent
. Несмотря на то что struct dirent
содержит несколько элементов, единственным переносимым элементом является d_name
, содержащий имя файла элемента каталога. Остальные элементы struct dirent
зависят от системы. Однако интересным является элемент d_ino
, содержащий inode-номер файла.
Самой сложной частью этого процесса является определение ошибки. К сожалению, readdir()
возвращает NULL
, и когда происходит ошибка, и когда в каталоге больше нет элементов. Чтобы различать эти две ситуации, необходимо проверять errno
. Эта задача усложняется тем, что readdir()
не меняет errno
, пока не произойдет ошибка. Это означает, что для корректной проверки ошибок errno
необходимо установить перед вызовом readdir()
в заранее известное значение (обычно 0). Ниже показана простая программа, записывающая имена файлов текущего каталога в stdout.
1: /* dircontents.с */
2:
3: #include
4: #include
5: #include
6:
7: int main(void) {
8: DIR * dir;
9: struct dirent * ent;
10:
11: /* "." - текущий каталог */
12: if (!(dir = opendir("."))) {
13: perror("opendir");
14: return 1;
15: }
16:
17: /* установить errno в 0, чтобы можно было выяснить, когда readdir() даст сбой*/
18: errno = 0;
19: while ((ent = readdir(dir))) {
20: puts (ent->d_name);
21: /* сбросить errno, поскольку puts() может модифицировать ее */
22: errno = 0;
23: }
24:
25: if (errno) {
26: perror("readdir");
27: return 1;
28: }
29:
30: closedir(dir);
31:
32: return 0;
33: }
14.4.1. Прохождение по каталогу
Если требуется перечитать содержимое каталога, уже открытого opendir()
, с помощью rewinddir()
структура DIR
сбрасывается, чтобы следующий вызов readdir()
мог вернуть первый файл в каталоге.
#include
int rewinddir(DIR * dir);
14.5. Универсализация файловых имен
Большинство пользователей Linux принимают как должное то, что запуск ls *.с
не сообщает сведения о файле в текущем каталоге, именем которого является *.с
. Вместо этого они ожидают увидеть список всех файлов в текущем каталоге, имена которых заканчиваются на .с
. Это расширение имени файла от *.с
до ladsh.с dircontents.с
(например) обычно обрабатывается оболочкой, которая универсализирует все параметры для программ, выполняющихся под ее управлением. Программы, помогающие пользователям манипулировать файлами, тоже часто нуждаются в универсализации файловых имен. Существуют два распространенных способа универсализации имен файлов внутри программ.
14.5.1. Использование подпроцесса
Самый старый метод универсализации предусматривает запуск оболочки в качестве дочернего процесса и указание ей универсализировать файловые имена. Стандартная функция popen()
(см. главу 10) упрощает этот метод — просто запустите команду ls *.с
с помощью popen()
и прочитайте результат. Этот подход может показаться несколько упрощенным, но все же он обеспечивает переносимое решение проблемы универсализации (вот почему приложения вроде Perl используют его).
Ниже приведена программа, которая универсализирует все аргументы и отображает все совпадения.
Читать дальше