递归降序遍历目录层次结构,并按文件类型计数

本程序使用了一些对目录进行操作的函数编写了一个遍历文件层次结构的程序,最后对各种类型的文件计数。这个程序只有一个参数,它说明起点路径名,从该点开始递归降序遍历文件层次结构。其中还用到了一个为路径名动态分配存储区的函数path_alloc。

// ftw.c// 2015-08-18 Lucifer Zhang// Recursively descend a directory hierarchy, counting file types#include "apue.h"#include "pathalloc.h"#include <dirent.h>#include <limits.h>// function type that is called for each filenametypedef 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 <starting-pathname>");}ret = myftw(argv[1], myfunc); // does it allntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;if (ntot == 0) {ntot = 1; // avoid divide by 0; print 0 for all counts}printf("regular files = %7ld, %5.2f %%\n", nreg, nreg * 100.0 / ntot);printf("directories = %7ld, %5.2f %%\n", ndir, ndir * 100.0 / ntot);printf("block special = %7ld, %5.2f %%\n", nblk, nblk * 100.0 / ntot);printf("char special = %7ld, %5.2f %%\n", nchr, nchr * 100.0 / ntot);printf("FIFLs= %7ld, %5.2f %%\n", nfifo, nfifo * 100.0 / ntot);printf("symbolic links = %7ld, %5.2f %%\n", nslink, nslink * 100.0 / ntot);printf("sockets= %7ld, %5.2f %%\n", nsock, nsock * 100.0 / ntot);exit(ret);}/* * Descend through the hierarchy starting at "pathname". * The caller's func() is called for every file. * */#define FTW_F 1 // file other than directory#define FTW_D 2 // directory#define FTW_DNR 3 // directory thar can't be read#define FTW_NS 4 // file that we can't statstatic char *fullpath; // contains full pathname for every filestatic size_t pathlen;static int myftw(char *pathname, Myfunc *func) // we return whatever func() returns{fullpath = path_alloc(&pathlen); // malloc PATH_MAX+1 bytesif (pathlen <= strlen(pathname)) {pathlen = strlen(pathname) * 2;if ((fullpath = realloc(fullpath, pathlen)) == NULL) {err_sys("realloc failed");}}strcpy(fullpath, pathname);return (dopath(func));}/* * Descend through the hierarchy, starting at "fullpath". * If "fullpath" is anything other than a directory, we lstat() it * call func(), and return. For a directory, we call ourself * recursively for each name in the directory. * */static int dopath(Myfunc *func) // we return whatever func() returns{struct stat statbuf;struct dirent *dirp;DIR * dp;int ret, n;if (lstat(fullpath, &statbuf) < 0) { // stat errorreturn (func(fullpath, &statbuf, FTW_NS));}if (S_ISDIR(statbuf.st_mode) == 0) { // not a directoryreturn (func(fullpath, &statbuf, FTW_F));}/** It's a directory. First call func() for the directory,* then process each filename in the directory.* */if ((ret = func(fullpath, &statbuf, FTW_D)) != 0) {return ret;}n = strlen(fullpath);if (n + NAME_MAX +2 > pathlen) { // expand path bufferpathlen *= 2;if ((fullpath = realloc(fullpath, pathlen)) == NULL) {err_sys("realloc failed");}}fullpath[n++] = '/';fullpath[n] = 0;if ((dp = opendir(fullpath)) == NULL) { // can't read directoryreturn func(fullpath, &statbuf, FTW_DNR);}while ((dirp = readdir(dp)) != NULL) {if (strcmp(dirp->d_name, ".") == 0 ||strcmp(dirp->d_name, "..") == 0) {continue; // ignore dot and dot-dot}strcpy(&fullpath[n], dirp->d_name); // append name agter "/"if ((ret = dopath(func)) != 0) { // recursivebreak; // time to leave}}fullpath[n – 1] = 0; // erase everything from slash onwardif (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: // directories should have type = FTW_Derr_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", type, pathname);}return 0;}// pathalloc.h// 2015-08-18 Lucifer Zhang// Dynamically allocate space for a pathname#include "apue.h"#include <errno.h>#include <limits.h>#ifdef PATH_MAXstatic long pathmax = PATH_MAX;#elsestatic long pathmax = 0;#endifstatic long posix_version = 0;static long xsi_version = 0;// If PATH_MAX is indeterminate, no guarantee this is adequate#define PATH_MAX_GUESS 1024char* path_alloc(size_t *sizep) { // also return allocated size, if nonnullchar *ptr;size_t size;if (posix_version == 0) {posix_version = sysconf(_SC_VERSION);}if (xsi_version == 0) {xsi_version = sysconf(_SC_XOPEN_VERSION);}if (pathmax == 0) { // first time througherrno = 0;if ((pathmax = pathconf("/", _PC_PATH_MAX)) < 0) {if (errno == 0) {pathmax = PATH_MAX_GUESS; // it's indeterminate} else {err_sys("pathconf error for _PC_PATH_MAX");}} else {++pathmax; // and one since it's relative to root}}/** Before POSIX.1-2001, we aren't guaranteed that PHAT_MAX includes* the terminating null byte. Same goes for XPG3.*/if ((posix_version < 200112L) && (xsi_version < 4)) {size = pathmax + 1;} else {size = pathmax;}if ((ptr = malloc(size)) == NULL) {err_sys("malloc error for pathname");}if (sizep != NULL) {*sizep = size;}return ptr;}Centos6.7上的测试结果:

版权声明:本文为博主原创文章,,未经博主允许不得转载。

天上永远不会掉馅饼,不要因为贪图一时的快乐而付出惨痛的代价,

递归降序遍历目录层次结构,并按文件类型计数

相关文章:

你感兴趣的文章:

标签云: