本文记录《UNIX高级环境编程》一书中,递归遍历目录树的程序:1.程序4-22递归降序遍历目录层次结构,并按照文件类型进行计数。主要涉及到三个函数myftw()、dopath()和myfunc()。myftw ()函数以所带参数pathname为要遍历的起始目录,计算出该目录下各种不同类型的文件的个数和所占百分比,并显示出来。它调用了另外两个函数,一个是dopath()函数,这是一个递归函数,对指定的起始目录下的每个目录项,按深度优先进行遍历;而对所访问的节点,则调用myfunc()进行处理。main函数输出统计结果。三个函数的参数含义如下:
(1) static int myftw(char *pathname, Myfunc *func);
pathname给出指要遍历开始的目录。
func是Myfunc类型的函数指针,定义访问的实际操作。
(2) static int dopath(Myfunc *func);
pathname给出指要遍历开始的目录。
(3) static int myfunc(const char *pathname, const struct stat *statptr, int type);
pathname指向当前访问节点的路径名。
statptr指向当前访问节点的i-节点的结构,该结构保存有许多该文件的信息。
type给出当前访问节点的类型,在实验中可以自己定义它的含义。
myfunc()的返回值通常是0,实际上在程序4-22中它的值总是0。但是在dopath()函数中,myfunc()的返回值非0意味着终止遍历。
另外,程序4-22中用到的函数path_alloc()用于分配存放路径名的内存空间。
`#include “apue.h”
#include <dirent.h>
#include <limits.h>
typedef int Myfunc(const char *,const struct stat *,int);
static Myfunc myfunc;
static int myftw(char *, Myfunc *);
static int dopath(Myfunc *);
static long nreg,ndir,nblk,nchr,nfifo,nslink,nsock,ntot;
int main(int argc, char argv[])
{
int ret;
if(argc!=2)
err_quit("usage: ftw ");
ret=myftw(argv[1],myfunc);
ntot=nreg+ndir+nblk+nchr+nfifo+nslink+nsock;
if(ntot==0)
ntot=1;
printf(“regular files = %5d, %5.2f %%\n”,nreg,nreg100.0/ntot );
printf(“directories = %5d, %5.2f %%\n”,ndir,ndir100.0/ntot );
printf(“block special = %5d, %5.2f %%\n”,nblk,nblk100.0/ntot );
printf(“char special = %5d, %5.2f %%\n”,nchr,nchr100.0/ntot );
printf(“FIFOs = %5d, %5.2f %%\n”,nfifo,nfifo100.0/ntot );
printf(“symbolic links = %5d, %5.2f %%\n”,nslink,nslink100.0/ntot );
printf(“sockets = %5d, %5.2f %%\n”,nsock,nsock100.0/ntot );
exit(ret);
}
#define FTW_F 1
#define FTW_D 2
#define FTW_DNR 3
#define FTW_NS 4
static char *fullpath;
static size_t pathlen;
static int myftw(char *pathname,Myfunc *func)
{
fullpath=path_alloc(&pathlen);
if (pathlen <= strlen(pathname))
{
pathlen=strlen(pathname)*2;
if((fullpath=realloc(fullpath,pathlen))==NULL)
err_sys("realloc failed");
}
strcpy(fullpath,pathname);
return(dopath(func));
}
static int dopath(Myfunc* func)
{
struct stat statbuf;
struct dirent *dirp;
DIR *dp;
int ret,n;
if (lstat(fullpath,&statbuf) < 0)
return(func(fullpath, &statbuf, FTW_NS));
if(S_ISDIR(statbuf.st_mode) == 0)
return(func(fullpath, &statbuf, FTW_F));
if((ret = func(fullpath, &statbuf, FTW_D)) != 0)
return(ret);
n=strlen(fullpath);
if(n+NAME_MAX+2 > pathlen){
pathlen*=2;
if((fullpath=realloc(fullpath,pathlen))==NULL)
err_sys("realloc failed");
}
fullpath[n++]='/';
fullpath[n]=0;
if((dp = opendir(fullpath))==NULL)
return(func(fullpath,&statbuf,FTW_DNR));
while((dirp = readdir(dp))!=NULL){
if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0)
continue;
strcpy(&fullpath[n],dirp->d_name);
if(ret = dopath(func)!=0)
break;
}
fullpath[n-1]=0;
if(closedir(dp)<0)
err_ret("can't close directory %s",fullpath);
return(ret);
}
static int myfunc(const char *pathname, const struct stat *statptr, int type)
{
switch (type) {
case FTW_F:
switch (statptr->st_mode & S_IFMT){
case S_IFREG: nreg++; break;
case S_IFBLK: nblk++; break;
case S_IFCHR: nchr++; break;
case S_IFIFO: nfifo++; break;
case S_IFLNK: nslink++; break;
case S_IFSOCK: nsock++; break;
case S_IFDIR:err_dump(“for S_IFDIR for %s”,pathname);
}
break;
case FTW_D:
ndir++;
break;
case FTW_DNR:
err_ret(“can’t read directory %s”,pathname) ;
break;
case FTW_NS:
err_ret(“stat error for %s”,pathname) ;
break;
default:
err_dump(“unknow type %d for pathname %s”,pathname) ;
}
return(0);
}
`
运行结果: