Книга: Основы программирования в Linux

closedir

closedir

Функция closedir закрывает поток каталога и освобождает ресурсы, выделенные ему. Она возвращает 0 в случае успеха и -1 при наличии ошибки.

#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);

В приведенной далее программе printdir.c (упражнение 3.4) вы соберете вместе множество функций обработки файлов для создания простого перечня содержимого каталога. Каждый файл представлен отдельной строкой. У каждого подкаталога есть имя, за которым следует слэш, и файлы, содержащиеся в подкаталоге, выводятся с отступом шириной в четыре пробела.

Программа превращает каталог в подкаталоги, чтобы у найденных файлов были пригодные для использования имена, т.е. они могут передаваться непосредственно в функцию opendir. Программа будет давать сбои при просмотре структур с большим числом уровней вложенности, поскольку есть ограничение на разрешенное число открытых потоков каталогов.

Мы могли бы сделать программу более универсальной, принимая в качестве аргумента командной строки начальную точку просмотра.

Для того чтобы познакомиться с методами повышения универсальности программ, посмотрите исходный код таких утилит Linux, как ls и find.

Упражнение 3.4. Программа просмотра каталога

1. Начните с соответствующих заголовочных файлов и функции printdir, которая выводит содержимое текущего каталога. Она будет рекурсивно вызываться для вывода подкаталогов, применяя параметр depth для задания отступа.

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
void printdir(char *dir, int depth) {
 DIR *dp;
 struct dirent *entry;
 struct stat statbuf;
 if ((dp = opendir(dir)) == NULL) {
  fprintf(stderr, "cannot open directory: %sn", dir);
  return;
 }
 chdir(dir);
 while((entry = readdir(dp)) != NULL) {
  lstat(entry->d_name, &statbuf);
  if (S_ISDIR(statbuf.st_mode)) {
   /* Находит каталог, но игнорирует . и .. */
   if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)
    continue;
   printf("%*s%s/n", depth, "", entry->d_name);
   /* Рекурсивный вызов с новый отступом */
   printdir(entry->d_name, depth+4);
  } else printf("%*s%sn", depth, " ", entry->d_name);
 }
 chdir("..");
 closedir(dp);
}

2. Теперь переходите к функции main.

int main() {
 /* Обзор каталога /home */
 printf("Directory scan of /home:n");
 printdir("/home", 0);
 printf("done.n");
 exit(0);
}

Программа просматривает исходные каталоги и формирует вывод, похожий на приведенный далее (отредактированный для краткости). Для того чтобы заглянуть в каталоги других пользователей, вам могут понадобиться права доступа суперпользователя.

$ ./printdir
Directory scan of /home:
neil/
    .Xdefaults
    .Xmodmap
    .Xresources
    .bash_history
    .bashrc
    .kde/
        share/
            apps/
                konqueror/
                    dirtree/
                        public_html.desktop
                    toolbar/
                        bookmarks.xml
                        konq_history
                    kdisplay/
                        color-schemes/
    BLP4e/
        Gnu_Public_License
        chapter04/
            argopt.с
            args.с
        chapter03/
            file.out
            mmap.с
            printdir
done.

Как это работает

Большинство операций сосредоточено в функции printdir. После некоторой начальной проверки ошибок с помощью функции opendir, проверяющей наличие каталога, printdir выполняет вызов функции chdir для заданного каталога. До тех пор пока элементы, возвращаемые функцией readdir, не нулевые, программа проверяет, не является ли очередной элемент каталогом. Если нет, она печатает элемент-файл с отступом, равным depth.

Если элемент — каталог, вы встречаетесь с рекурсией. После игнорирования элементов . и .. (текущего и родительского каталогов) функция printdir вызывает саму себя и повторяет весь процесс снова. Как она выбирается из этих повторений? Как только цикл while заканчивается, вызов chdir("..") возвращает программу вверх по дереву каталогов, и предыдущий перечень можно продолжать. Вызов closedir(dp) гарантирует, что количество открытых потоков каталогов не больше того, которое должно быть.

Для того чтобы составить представление об окружении в системе Linux, обсуждаемом в главе 4, познакомьтесь с одним из способов, повышающих универсальность программы. Рассматриваемая программа ограничена, потому что привязана каталогу /home. Следующие изменения в функции main могли бы превратить эту программу в полезный обозреватель каталогов:

int main(int argc, char* argv[]) {
 char *topdir = ".";
 if (argc >= 2) topdir = argv[1];
 printf("Directory scan of %sn", topdir);
 printdir(topdir, 0);
 printf("done.n");
 exit(0);
}

Три строки изменены и пять добавлено, но это уже универсальная утилита с необязательным параметром, содержащим имя каталога, по умолчанию равным текущему каталогу. Вы можете выполнять ее с помощью следующей командной строки:

$ ./printdir2 /usr/local | more

Вывод будет разбит на страницы, и пользователь сможет листать их. Таким образом, у него появится маленький удобный универсальный обозреватель дерева каталогов. Приложив минимум усилий, вы могли бы добавить статистический показатель использования пробелов, предельную глубину отображения и т.д.

Оглавление книги

Оглавление статьи/книги

Генерация: 1.590. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз