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

readdir函数的使用方式

头文件:
#include   
#include 
定义函数:
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 
#include 
#include 
#include 
#include 
#include 
#include 

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语言)