美文网首页
Linux统计目录内的文件 c语言

Linux统计目录内的文件 c语言

作者: xiamigan | 来源:发表于2018-10-08 22:34 被阅读0次

    readdir函数的使用方式

    头文件:
    #include <sys/types.h>  
    #include <dirent.h>
    定义函数:
    struct dirent * readdir(DIR * dir);
    

    函数说明:
    返回值:成功则返回下个目录进入点。有错误发生或读取到目录文件尾则返回NULL.
    结构体dirent 定义如下(在linux下搜索dirent.h即可找到):

    struct dirent
      {
    #ifndef __USE_FILE_OFFSET64
        __ino_t d_ino;
        __off_t d_off;
    #else
        __ino64_t d_ino;
        __off64_t d_off;
    #endif
        unsigned short int d_reclen;
        unsigned char d_type;
        char d_name[256];       /* We must not include limits.h! */
      };
    

    调用opendir和readdir函数对指定目录进行遍历操作,然后打印输出指定目录中各种类型的文件数目。

    #include <stdio.h>
    #include <fcntl.h>
    #include <dirent.h>
    #include <limits.h>
    #include <sys/stat.h>
    #include <string.h>
    #include <stdlib.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;
    //各种类型的文件数目对应的变量
    char *path_alloc(int* size);
    
    int main(int argc, char *argv[])
    {
      int ret;
      if (argc != 2)
      {
         printf("请输入正确的参数!\n");   //参数错误
         return 1;
      }
      ret = myftw(argv[1], myfunc);     /* does it all */
      ntot = nreg + ndir + nblk + nchr + nfifo + nslink + nsock;
      //计算文件总量
      if (ntot == 0)     //如果目录中没有文件则将ntot设置为1以避免除数为0
      {
        ntot = 1;   
      }
      //以下一次打印各种类型文件的数据
      printf("普通文件 = %7ld, %5.2f %%\n", nreg, nreg*100.0/ntot);
      printf("目录文件 = %7ld, %5.2f %%\n", ndir,ndir*100.0/ntot);
      printf("块设备文件 = %7ld, %5.2f %%\n", nblk,nblk*100.0/ntot);
      printf("字设备文件 = %7ld, %5.2f %%\n", nchr, nchr*100.0/ntot);
      printf("FIFOs = %7ld, %5.2f %%\n", nfifo,nfifo*100.0/ntot);
      printf("符号链接文件 = %7ld, %5.2f %%\n", nslink, nslink*100.0/ntot);
      printf("套接字文件 = %7ld, %5.2f %%\n", nsock,nsock*100.0/ntot);
      return ret;
    }
    //路径缓冲区分配函数
    char *path_alloc(int* size)
    {
      char *p = NULL;
      if(!size)
      { 
        return NULL;
      }
      p = malloc(256);
      if(p)
      {
        *size = 256;
      }
      else
      {
        *size = 0;
      }
      return p;
    }
    
    #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)
    {
      int len;
      fullpath = path_alloc(&len);  //给路径缓冲区分配一个长度
      strncpy(fullpath, pathname, len); //复制文件名称
      fullpath[len-1] = 0;  //给缓冲区的最后一位赋'\0'        
      return(dopath(func));
    }
    
    //获得文件的状态的函数
    static int dopath(Myfunc* func)
    {
      struct stat   statbuf;
      struct dirent *dirp;
      DIR *dp;
      int ret;     //返回标记值,用于
      char *ptr;  //用于给fullpath加字符串,用来做子目录探索
      if (lstat(fullpath, &statbuf) < 0)    //获得文件状态失败就执行,其中lstat函数成功执行时,返回0。失败返回-1
      {
        return(func(fullpath, &statbuf, FTW_NS));//工作正常时返回值为0
      }
      if (S_ISDIR(statbuf.st_mode) == 0)    //如果不是目录,则。。。
      {                                   //其中S_ISDIR为宏函数,用于判断是否目录,如果是目录,返回值为1
        return(func(fullpath, &statbuf, FTW_F));//工作正常时返回值为0
      }
      if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)//经过以上if语句,运行到这一步的为目录文件,调用myfunc函数,目录记录数+1,然后记录成功的话,ret的值为0,if中的语句就不会执行
      {          
        return(ret);//myfunc工作正常时返回值ret为0
      }
      ptr = fullpath + strlen(fullpath);    //指向路径缓冲区字符串的结尾,此时*ptr='/0'
      *ptr++ = '/'; //相当于*ptr='/';ptr++;
      *ptr = 0;//当前位置'\0',用于字符串结尾定位,防止输出乱码
      //---------------------------------------------------------------------------------------------------------------
      //获得子目录文件的信息
      if ((dp = opendir(fullpath)) == NULL) //调用opendir,其返回值为一个DIR类型指针,如果值为NULL则读取错误或位于目录尾
      {
        return(func(fullpath, &statbuf, FTW_DNR));//调用myfunc函数,不可读的目录+1
      }
      while ((dirp = readdir(dp)) != NULL) /*关键点!!readdir函数返回指向dirent结构体类型的指针,返回值:成功则返回下个目录进入点. 有错误发生或读取到目录文件尾则返回NULL.  */
      {
            if (strcmp(dirp->d_name, ".") == 0  ||strcmp(dirp->d_name, "..") == 0)//strcmp函数,如果两个字符串相同则返回0
                    continue;                   /* 忽略.. 和. 文件 */
            strcpy(ptr, dirp->d_name);  /*把子文件名加入到*fullpath字符串后面,生成新的详细路径*/
            if ((ret = dopath(func)) != 0)      /* 嵌套获取当前的路径的信息,如果有多个子目录或者多个子文件,都进行统计 */
                break;//if语句是为了让程序运行出错就跳出当前循环
        }
      //---------------------------------------------------------------------------------------------------------------
      ptr--;
        ptr = 0;    /* 通过给斜线处赋值为'\0',相当于删除斜线后面添加的内容,此处书上是ptr[-1]=0 */
    
        if (closedir(dp) < 0)
        {
            printf("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++;     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:
                printf("for S_IFDIR for %s\n", pathname);
            }
            break;
    
        case FTW_D:
            ndir++;
            break;
        case FTW_DNR:
            printf("can't read directory %s\n", pathname);
            break;
        case FTW_NS:
            printf("stat error for %s\n", pathname);
            break;
        default:
            printf("unknown type %d for pathname %s\n", type, pathname);
        }
        return(0);
    }
    

    相关文章

      网友评论

          本文标题:Linux统计目录内的文件 c语言

          本文链接:https://www.haomeiwen.com/subject/gmlsaftx.html