Реализации на основе opendir (), readdir () и closedir () почти никогда не обрабатывают случаи, когда каталоги или файлы перемещаются, переименовываются или удаляются во время обхода дерева.nftw () должен обрабатывать их правильно
Для обхода файлового дерева есть две функции.ftw () и nftw ().ftw () проходит по дереву каталогов, которое находится под каталогом dirpath, и вызывает fn () один раз для каждой записи в дереве.По умолчанию каталоги обрабатываются до файлов и подкаталогов, которые они содержат (обход по предварительному заказу).
* int ftw (const char * dirpath, int (* fn) (const char * fpath, conststruct stat sb, int typeflag), int nopenfd);
Функция nftw () такая же, как ftw (), за исключением того, что она имеет один дополнительный аргумент, flags,и вызывает fn () с еще одним аргументом, ftwbuf.Этот аргумент флагов формируется путем ORing нуля или более из следующих флагов:
int nftw (const char * dirpath, int (* fn) (const char * fpath, const struct stat * sb, inttypeflag, struct FTW * ftwbuf), int nopenfd, int flags);
Эти функции возвращают 0 в случае успеха и -1 в случае ошибки.
Следующая программа перебираетдерево каталогов по пути, указанному в первом аргументе командной строки, или по текущему каталогу, если аргумент не указан.Он отображает различную информацию о каждом файле.
#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
static int display_info(const char *fpath, const struct stat *sb,
int tflag,struct FTW *ftwbuf)
{
printf("%-3s %2d %7jd %-40s %d %s\n",
(tflag == FTW_D) ? "d" : (tflag == FTW_DNR) ? "dnr" :
(tflag == FTW_DP) ? "dp" : (tflag == FTW_F) ? "f" :
(tflag == FTW_NS) ? "ns" : (tflag == FTW_SL) ? "sl" :
(tflag == FTW_SLN) ? "sln" : "???",
ftwbuf->level, (intmax_t) sb->st_size,
fpath, ftwbuf->base, fpath + ftwbuf->base);
return 0; /* To tell nftw() to continue */
}
int main(int argc, char *argv[])
{
int flags = 0;
if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags)
== -1) {
perror("nftw");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}