- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Linux программирование в примерах - Арнольд Роббинс
Шрифт:
Интервал:
Закладка:
Давайте свяжем все это воедино в примере программы. ch08-nftw.c обрабатывает каждый файл или каталог, указанный в командной строке, запуская для них nftw(). Функция, обрабатывающая каждый файл, выводите отступом имя и тип файла, показывая иерархическое положение каждого файла. Для разнообразия мы сначала покажем результаты, а затем покажем и обсудим программу:
$ pwd /* Где мы находимся */
/ home/аrnold/work/prenhall/progex
$ code/ch08/ch08-nftw code /* Обойти каталог 'code' */
code (directory) /* Каталог верхнего уровня */
ch02 (directory) /* Подкаталоги с отступом на один уровень */
ch02-printenv.c (file) /* Файлы в подкаталоге с отступом
на два уровня */
ch03 (directory)
ch03-memaddr.c (file)
ch04 (directory)
ch04-holes.c (file)
ch04-cat.с (file)
ch04-maxfds.c (file)
v7cat.c (file)
...
Вот сама программа:
1 /* ch08-nftw.c --- демонстрирует nftw() */
2
3 #define _XOPEN_SOURCE 1 /* Требуется под GLIBC для nftw() */
4 #define _XOPEN_SOURCE_EXTENDED 1 /* To же */
5
6 #include <stdio.h>
7 #include <errno.h>
8 #include <getopt.h>
9 #include <ftw.h> /* получает для нас <sys/types.h> и <sys/stat.h> */
10 #include <limits.h> /* для PATH_MAX */
11 #include <unistd.h> /* для объявлений getdtablesize(), getcwd() */
12
13 #define SPARE_FDS 5 /* fds для использования другими функциями, см. текст */
14
15 extern int process(const char *file, const struct stat *sb,
16 int flag, struct FTW *s);
17
18 /* usage --- print message and die */
19
20 void usage(const char *name)
21 {
22 fprintf(stderr, "usage: %s (-c) directory ...n", name);
23 exit(1);
24 }
25
26 /* main --- вызвать nftw() для каждого аргумента командной строки */
27
28 int main(int argc, char **argv)
29 {
30 int i, c, nfds;
31 int errors = 0;
32 int flags = FTW_PHYS;
33 char start[PATH_MAX], finish[PATH_MAX];
34
35 while ((c = getopt(argc, argv, "с")) != -1) {
36 switch (c) {
37 case 'c':
38 flags |= FTW_CHDIR;
39 break;
40 default:
41 usage(argv[0]);
42 break;
43 }
44 }
45
46 if (optind == argc)
47 usage(argv[0]);
48
49 getcwd(start, sizeof start);
50
51 nfds = getdtablesize() - SPARE_FDS; /* оставить несколько запасных дескрипторов */
52 for (i = optind; i < argc; i++) {
53 if (nftw(argv[i], process, nfds, flags) != 0) {
54 fprintf(stderr, "%s: %s: stopped earlyn",
55 argv[0], argv[i]);
56 errors++;
57 }
58 }
59
60 if ((flags & FTW_CHDIR) != 0) {
61 getcwd(finish, sizeof finish);
62 printf("Starting dir: %sn", start);
63 printf("Finishing dir: %sn", finish);
64 }
65
66 return (errors != 0);
67 }
Строки 3–11 включают заголовочные файлы. По крайней мере в GLIBC 2.3.2 перед включением любого заголовочного файла необходимы #define для _XOPEN_SOURCE и _XOPEN_SOURCE_EXTENDED. Они дают возможность получить объявления и значения флагов, которые nftw() предоставляет свыше предоставляемых ftw(). Это специфично для GLIBC. Потребность в этом в конечном счете исчезнет, когда GLIBC станет полностью совместимой со стандартом POSIX 2001.
Строки 35–44 обрабатывают опции. Опция -с добавляет к флагам nftw() FTW_CHDIR. Это эксперимент с целью увидеть, сможете ли вы оказаться где-то в другом месте от того, где начинали. Кажется, это возможно, если nftw() завершается неудачей, в противном случае вы заканчиваете там же, где начинали. (POSIX не документирует это явным образом, но целью, похоже, было действительно заканчивать там же, где начинали. Стандарт не говорит, что функция обратного вызова не должна менять текущий каталог.)
Строка 49 сохраняет начальный каталог для дальнейшего использования, пользуясь getcwd().
Строка 51 вычисляет число дескрипторов, которые может использовать nftw(). Мы не хотим, чтобы она использовала все доступные дескрипторы файлов, если функция обратного вызова также хочет открывать файлы. В вычислении используется getdtablesize() (см. раздел 4.4.1 «Понятие о дескрипторах файлов») для получения максимально возможного числа и вычета из него SPARE_FDS, который был вычислен ранее в строке 13.
Эта процедура служит основанием для больших объяснений. В обычном случае по крайней мере три дескриптора уже используются для стандартного ввода, стандартного вывода и стандартной ошибки. nftw() нужно некоторое количество дескрипторов файлов для открытия и чтения каталогов; внутри себя opendir() использует open() при открытии каталогов для чтения. Если функции обратного вызова также нужно открывать файлы, мы должны предотвратить израсходование функцией nftw() всех доступных дескрипторов файлов для открывания каталогов. Мы делаем это, вычитая некоторое число из максимально допустимого. Для данного примера мы выбрали пять, но если функции обратного вызова нужно открывать файлы, должно использоваться большее число, (nftw() знает, как восстановиться при израсходовании дескрипторов файлов; мы не должны беспокоиться о таком случае.)
Строки 52–58 являются главным циклом над нашими аргументами; строки 53–57 проверяют ошибки; когда они появляются, код выводит диагностическое сообщение и увеличивает значение переменной errors.
Строки 60–64 являются частью эксперимента с FTW_CHDIR, выводящего начальный и конечный каталоги, если было использовано -с.
По-настоящему интересной функцией является process(); это функция обратного вызова, которая обрабатывает каждый файл. Она использует базовый шаблон для функции обратного вызова nftw(), который является оператором switch для значения flag.
69 /* process --- выводит каждый файл на нужном уровне */
70
71 int process(const char "file, const struct stat *sb,
72 int flag, struct FTW *s)
73 {
74 int retval = 0;
75 const char *name = file + s->base;
76
77 printf("%*s", s->level * 4, ""); /* сделать отступ */
78
79 switch (flag) {
80 case FTW_F:
81 printf("%s (file)n", name);
82 break;
83 case FTW_D:
84 printf("%s (directory)n", name);
85 break;
86 case FTW_DNR:
87 printf("%s (unreadable directory)n", name);
88 break;
89 case FTW_SL:
90 printf("%s (symbolic link)n", name);
91 break;
92 case FTW_NS:
93 printf("%s (stat failed): %sn", name, strerror(errno));
94 break;
95 case FTW_DP:
96 case FTW_SLN:
97 printf("%s: FTW_DP or FTW_SLN: can't happen'n", name);
98 retval = 1;
99 break;
100 default:
101 printf("%s: unknown flag %d: can't happen'n", name, flag);
102 retval = 1;
103 break;
104 }
105
106 return retval;
107 }
Строка 75 использует 'file + s->base' для получения имени из полного пути. Это значение указателя сохраняется в переменной name для повторного использования в функции.
Строка 77 делает отступ нужного размера, используя красивый трюк. Используя %*s, printf() получает от первого аргумента ширину поля. Это вычисляется динамически как 'level * 4'. Строка, которая должна быть выведена — «», пустая строка. Конечным результатом является то, что printf() создает для нас отступ нужного размера без необходимости запуска цикла.
Строки 79–104 являются оператором switch. В данном случае он не делает ничего весьма интересного, кроме вывода имени файла и его типа (файл, каталог и т.д.)
Хотя эта программа не использует struct stat, должно быть ясно, что вы могли бы сделать в функции обратного вызова все, что хотите.
ЗАМЕЧАНИЕ. Джим Мейеринг (Jim Meyering), сопроводитель GNU Coreutils, замечает, что дизайн nftw() несовершенен из-за ее рекурсивной природы. (Она рекурсивно вызывает себя при обработке подкаталогов.) Если иерархия каталогов становится действительно глубокой, в диапазоне уровней 20 000–40 000 (!), nftw() может выйти за пределы размера стека, уничтожив программу. Есть также и другие проблемы, связанные с дизайном nftw(). Версия GNU Coreutils после 5.0 исправляет это путем использования набора процедур fts() (см. fts(3)).
8.5. Обход дерева файлов: GNU du

