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);
}