递归降序遍历目录层次结构,并按文件类型计数
2015-08-18 20:15
281 查看
本程序使用了一些对目录进行操作的函数编写了一个遍历文件层次结构的程序,最后对各种类型的文件计数。这个程序只有一个参数,它说明起点路径名,从该点开始递归降序遍历文件层次结构。其中还用到了一个为路径名动态分配存储区的函数path_alloc。
Centos6.7上的测试结果:
// 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 filename 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 <starting-pathname>"); } ret = myftw(argv[1], myfunc); // does it all ntot = 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 stat static char *fullpath; // contains full pathname for every file static size_t pathlen; static int myftw(char *pathname, Myfunc *func) // we return whatever func() returns { fullpath = path_alloc(&pathlen); // malloc PATH_MAX+1 bytes if (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 error return (func(fullpath, &statbuf, FTW_NS)); } if (S_ISDIR(statbuf.st_mode) == 0) { // not a directory return (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 buffer pathlen *= 2; if ((fullpath = realloc(fullpath, pathlen)) == NULL) { err_sys("realloc failed"); } } fullpath[n++] = '/'; fullpath = 0; if ((dp = opendir(fullpath)) == NULL) { // can't read directory return 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 , dirp->d_name); // append name agter "/" if ((ret = dopath(func)) != 0) { // recursive break; // time to leave } } fullpath[n - 1] = 0; // erase everything from slash onward 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: // directories should have type = FTW_D 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", 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_MAX static long pathmax = PATH_MAX; #else static long pathmax = 0; #endif static long posix_version = 0; static long xsi_version = 0; // If PATH_MAX is indeterminate, no guarantee this is adequate #define PATH_MAX_GUESS 1024 char* path_alloc(size_t *sizep) { // also return allocated size, if nonnull char *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 through errno = 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上的测试结果:
相关文章推荐
- 总线设备驱动模型
- 【Linux探索之旅】第一部分第五课:Unity桌面,人生若只如初见
- 集训第六周 古典概型 期望 D题 Discovering Gold 期望
- CODEVS 2055 集合划分
- “Adb connection Error:远程主机强迫关闭了一个现有的连接。”之我的解决方法。
- Android基础0818生命周期+LinearLayout+RelativeLayout
- Ubuntu:su切换用户时提示 su:认证失败
- OC 之block类型剖析
- 暑假-最短路(Bellman-ford、spfa)-C - Minimum Transport Cost
- 总线设备驱动模型——驱动篇
- Codeforces Gym 100650D Queens, Knights and Pawns 暴力
- 黑马程序员——视频学习过程4
- using声明和using指示、std::move和std::forward
- 10个前端开发必备的工具或使用方法
- HDOJ 1047 Integer Inquiry (多个大数求和)
- 图形验证码(JSP+Servlet)
- UVA 11997 K Smallest Sums
- Python nltk -- Sinica Treebank
- BZOJ1042
- Delphi 在任务栏隐藏程序图标