Б.6. Чтение содержимого каталога
В Linux имеются функции, предназначенные для чтения содержимого каталога. И хотя они не относятся к низкоуровневым функциям, мы все же решили их описать, так как они широко применяются в программах.
При чтении содержимого каталога необходимо придерживаться такой последовательности действий.
1. Вызовите функцию opendir()
, передав ей путевое имя требуемого каталога. Эта функция возвращает дескриптор типа DIR*
, который можно использовать для доступа к содержимому каталога. В случае ошибки возвращается NULL
.
2. Последовательно вызывайте функцию readdir()
, передавая ей дескриптор, полученный от функции opendir()
. Всякий раз функция readdir()
будет возвращать указатель на структуру типа dirent
, содержащую информацию о следующем элементе каталога. По достижении конца каталога будет получено значение NULL
. У структуры dirent
есть поле d_name
, где содержится имя элемента каталога.
3. Вызовите функцию closedir()
, передав ей имеющийся дескриптор, чтобы завершить сеанс работы с каталогом.
Для использования перечисленных функций необходимо включить в программу файлы и . Ответственность за сортировку содержимого каталога возлагается на программу.
В листинге Б.8 показана программа отображающая список содержимого каталога. Имя каталога задается в командной строке. Если этого не сделать, будет проанализирован текущий каталог. Для каждого элемента каталога отображается его тип и путевое имя. Функция get_file_type()
определяет тип объекта файловой системы с помощью функции lstat()
.
Листинг Б.8. ( listdir.c ) Вывод содержимого каталога
#include
#include
#include
#include
#include
#include
#include
/* Эта функция возвращает строку с описанием типа объекта
файловой системы, заданного в аргументе PATH. */
const char* get_file_type(const char* path) {
struct stat st;
lstat(path, &st);
if (S_ISLNK(st.st_mode))
return "symbolic link";
else if (S_ISDIR(st.st_mode))
return "directory";
else if (S_ISCHR(st.st_mode))
return "character device";
else if (S_ISBLK(st.st_mode))
return "block device";
else if (S_ISFIFO(st.st_mode))
return "fifo";
else if (S_ISSOCK(st.st_mode))
return "socket";
else if (S_ISREG(st.st_mode))
return "regular file";
else
/* Нераспознанный тип. */
assert(0);
}
int main(int argc, char* argv[]) {
char* dir_path;
DIR* dir;
struct dirent* entry;
char entry_path[PATH_MAX + 1];
size_t path_len;
if (argc >= 2)
/* Если каталог указан в командной строке, анализируем его. */
dir_path = argv[1];
else
/* В противном случае анализируем текущий каталог. */
dir_path = ".";
/* Копируем имя каталога в переменную entry_path. */
strncpy(entry_path, dir_path, sizeof(entry_path));
path_len = strlen(dir_path);
/* Если имя каталога не заканчивается косой чертой,
добавляем ее. */
if (entry_path[path_len - 1] != '/') {
entry_path[path_len] = '/';
entry_path[path_len + 1] = '\0';
++path_len;
}
/* Начинаем обрабатывать список содержимого каталога. */
dir = opendir(dir_path);
/* просматриваем все элементы каталога. */
while ((entry = readdir(dir)) != NULL) {
const char* type;
/* Формируем полное путевое имя элемента каталога. */
strncpy(entry_path + path_len, entry->d_name,
sizeof(entry_path) — path_len);
/* Определяем тип элемента. */
type = get_file_type(entry_path);
/* Отображаем собранную информацию. */
printf("%-18s: %s\n", type, entry_path);
}
/* Конец работы. */
closedir(dir);
return 0;
}
Приведем несколько строк листинга полученного в каталоге /dev
(в разных системах могут быть выданы разные результаты)
% ./listdir /dev
directory : /dev/.
directory : /dev/..
socket : /dev/log
character device : /dev/null
regular file : /dev/MAKEDEV
fifo : /dev/initctl
character device : /dev/agpgart
...
Для проверки этих данных можно воспользоваться командой ls
. Флаг -U
отменяет сортировку списка, а флаг -a
заставляет включить в список записи текущего ( .
) и родительского ( ..
) каталогов.
% ls -lua /dev total 124
drwxr-xr-x 7 root root 36864 Feb 1 15:14 .
drwxr-xr-x 22 root root 4096 Oct 11 16:39 ..
srw-rw-rw- 1 root root 0 Dec 18 01:31 log
crw-rw-rw- 1 root root 1, 3 May 5 1998 null
-rwxr-xr-x 1 root root 26689 Mar 2 2000 MAKEDEV
prw------- 1 root root 0 Dec 11 18:37 initctl
Читать дальше