《Unix环境高级编程》:递归遍历目录层次结构,并按文件类型计数

《Unix环境高级编程》这本书附带了许多短小精美的小程序,我在阅读此书的时候,将书上的代码按照自己的理解重写了一遍(大部分是抄书上的),加深一下自己的理解(纯看书太困了,呵呵)。此例子在Ubuntu10.04上测试通过。


程序简介:这是一个遍历文件层次结构的程序,目的是得到各种类型的文件数及其所占的比例。

//《APUE》程序4-7:
//递归遍历目录层次结构,并按文件类型计数
#include <unistd.h>
#include <utime.h>
#include <dirent.h>
#include <sys/stat.h>
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <string.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 )
	{
		fprintf(stderr, "Usage: ftw <starting-pathname>\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);
	return ret;
}

#define FTW_F 1
#define FTW_D 2
#define FTW_DNR 3
#define FTW_NS 4

static char *fullpath;

static int myftw(char *pathname, Myfunc *func)
{
	//《APUE》书中,这个功能用了一个很复杂的函数path_alloc()来实现
	//这里我为了简单起见,直接为它分配了一段内存完事
#ifdef PATH_MAX
	const int PATH_LEN = PATH_MAX;
#else
	const int PATH_LEN = 1024;
#endif

	fullpath = malloc(PATH_LEN);
	strncpy(fullpath, pathname, PATH_LEN);
	fullpath[PATH_LEN-1] = '\0';
	int res = dopath(func);
	//《APUE》书中,好像没有释放这段内存
	free(fullpath);
	return res;
}

static int dopath(Myfunc* func)
{
	struct stat statbuf;
	struct dirent *dirp;
	DIR *dp;
	int ret;
	char *ptr;

	int temp;
	temp = lstat(fullpath, &statbuf);
	//文件状态错误
	if( temp < 0 )
		return func(fullpath, &statbuf, FTW_NS);
	temp = S_ISDIR(statbuf.st_mode);
	//不是文件夹
	if( 0 == temp )
		return func(fullpath, &statbuf, FTW_F);

	ret = func(fullpath, &statbuf, FTW_D);
	if( ret != 0 )
		return ret;
	ptr = fullpath + strlen(fullpath);
	*ptr++ = '/';
	*ptr = 0;

	dp = opendir(fullpath);
	//不能读取该文件夹
	if( NULL == dp )
		return func(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) < 0 )
	{
		fprintf(stderr, "can't close directory %s\n", 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++; 
			printf("reg: %s\n", fullpath); 
			break;
		case S_IFBLK: 
			nblk++; 
			printf("blk: %s\n", fullpath); 
			break;
		case S_IFCHR: 
			nchr++; 
			printf("chr: %s\n", fullpath);
			break;
		case S_IFIFO: 
			nfifo++; 
			printf("fifo: %s\n", fullpath);
			break;
		case S_IFLNK: 
			nslink++; 
			printf("slink: %s\n", fullpath);
			break;
		case S_IFSOCK: 
			nsock++; 
			printf("socket: %s\n", fullpath);
			break;
		case S_IFDIR: 
			fprintf(stderr, "For S_IFDIR for %s\n", pathname);
			exit(1);
		}
		//《APUE》书中没有输出遍历的结果,这个是我自己加上去的
		break;
	case FTW_D:
		ndir++; 
		printf("DIR: %s\n", fullpath);
		break;
	case FTW_DNR:
		fprintf(stderr, "can't read directory %s\n", pathname);
		break;
	case FTW_NS:
		fprintf(stderr, "stat error for %s\n", pathname);
		break;
	default:
		fprintf(stderr, "unkown type %d for pathname %s\n", 
			type, pathname);
	}
	return 0;
}


运行示例(红色字体的为输入):

qch@ubuntu:~/code$ gcc temp.c -o temp

qch@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 % 

你可能感兴趣的:(struct,socket,ubuntu,null,Path,Sockets)