《Unix环境高级编程》这本书附带了许多短小精美的小程序,我在阅读此书的时候,将书上的代码按照自己的理解重写了一遍(大部分是抄书上的),加深一下自己的理解(纯看书太困了,呵呵)。此例子在Ubuntu 10.04上测试通过。
相关链接
//《APUE》程序4-7:
//递归遍历目录层次结构,并按文件类型计数
#include
#include
#include
#include
#include
#include
#include
#include
typedefintMyfunc(constchar*,conststructstat*,int);
staticMyfunc myfunc;
staticintmyftw(char*, Myfunc*);
staticintdopath(Myfunc*);
staticlongnreg, ndir, nblk, nchr, nfifo, nslink, nsock, ntot;
intmain(intargc,char**argv)
{
intret;
if( argc != 2 )
{
fprintf(stderr,"Usage: ftw \n");
exit(1);
}
ret = myftw(argv[1], myfunc);
ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
//
if( 0 == ntot )
ntot = 1;
//输入各种文件的数量及所占的比例
printf("reglar files = %7ld, %5.2lf %% \n",
nreg, nreg*100.0/ntot);
printf("directories = %7ld, %5.2lf %% \n",
ndir, ndir*100.0/ntot);
printf("block special = %7ld, %5.2lf %% \n",
nblk, nblk*100.0/ntot);
printf("char special = %7ld, %5.2lf %% \n",
nchr, nchr*100.0/ntot);
printf("FIFOs = %7ld, %5.2lf %% \n",
nfifo, nfifo*100.0/ntot);
printf("symbolic links = %7ld, %5.2lf %% \n",
nslink, nslink*100.0/ntot);
printf("sockets = %7ld, %5.2lf %% \n",
nsock, nsock*100.0/ntot);
returnret;
}
#define FTW_F 1
#define FTW_D 2
#define FTW_DNR 3
#define FTW_NS 4
staticchar*fullpath;
staticintmyftw(char*pathname, Myfunc *func)
{
//《APUE》书中,这个功能用了一个很复杂的函数path_alloc()来实现
//这里我为了简单起见,直接为它分配了一段内存完事
#ifdef PATH_MAX
constintPATH_LEN = PATH_MAX;
#else
constintPATH_LEN = 1024;
#endif
fullpath = malloc(PATH_LEN);
strncpy(fullpath, pathname, PATH_LEN);
fullpath[PATH_LEN-1] ='\0';
intres = dopath(func);
//《APUE》书中,好像没有释放这段内存
free(fullpath);
returnres;
}
staticintdopath(Myfunc* func)
{
structstat statbuf;
structdirent *dirp;
DIR *dp;
intret;
char*ptr;
inttemp;
temp = lstat(fullpath, &statbuf);
//文件状态错误
if( temp
returnfunc(fullpath, &statbuf, FTW_NS);
temp = S_ISDIR(statbuf.st_mode);
//不是文件夹
if( 0 == temp )
returnfunc(fullpath, &statbuf, FTW_F);
ret = func(fullpath, &statbuf, FTW_D);
if( ret != 0 )
returnret;
ptr = fullpath + strlen(fullpath);
*ptr++ ='/';
*ptr = 0;
dp = opendir(fullpath);
//不能读取该文件夹
if( NULL == dp )
returnfunc(fullpath, &statbuf, FTW_DNR);
while( (dirp = readdir(dp)) != NULL )
{
//忽略.和..这两个文件夹
if( strcmp(dirp->d_name,".") == 0 ||
strcmp(dirp->d_name,"..") == 0 )
continue;
strcpy(ptr, dirp->d_name);
//递归遍历各个子文件夹
ret = dopath(func);
if( ret != 0 )
break;
}
ptr[-1] = 0;
if( closedir(dp)
{
fprintf(stderr,"can't close directory %s\n", fullpath);
}
returnret;
}
staticintmyfunc(constchar*pathname,conststructstat *statptr,inttype)
{
switch(type)
{
caseFTW_F:
switch( statptr->st_mode & S_IFMT )
{
caseS_IFREG:
nreg++;
printf("reg: %s\n", fullpath);
break;
caseS_IFBLK:
nblk++;
printf("blk: %s\n", fullpath);
break;
caseS_IFCHR:
nchr++;
printf("chr: %s\n", fullpath);
break;
caseS_IFIFO:
nfifo++;
printf("fifo: %s\n", fullpath);
break;
caseS_IFLNK:
nslink++;
printf("slink: %s\n", fullpath);
break;
caseS_IFSOCK:
nsock++;
printf("socket: %s\n", fullpath);
break;
caseS_IFDIR:
fprintf(stderr,"For S_IFDIR for %s\n", pathname);
exit(1);
}
//《APUE》书中没有输出遍历的结果,这个是我自己加上去的
break;
caseFTW_D:
ndir++;
printf("DIR: %s\n", fullpath);
break;
caseFTW_DNR:
fprintf(stderr,"can't read directory %s\n", pathname);
break;
caseFTW_NS:
fprintf(stderr,"stat error for %s\n", pathname);
break;
default:
fprintf(stderr,"unkown type %d for pathname %s\n",
type, pathname);
}
return0;
}
运行示例(加下划线的为输入):
www.linuxidc.com @ubuntu:~/code$ gcc temp.c -o temp
www.linuxidc.com @ubuntu:~/code$ ./temp /etc
DIR: /etc
DIR: /etc/sudoers.d
reg: /etc/sudoers.d/README
...............
reglar files = 1593, 59.89 %
directories = 306, 11.50 %
block special = 0, 0.00 %
char special = 0, 0.00 %
FIFOs = 0, 0.00 %
symbolic links = 761, 28.61 %
sockets = 0, 0.00 %