11.分析目录/读取目录内容
glob(): 解析模式/通配符
1.能够实现下面函数所有操作
作用:帮忙分析pattern(通配符)
参数详解:
pattern: 模式或通配符
flags:以按位或的形式把0个或多个符号信息或进参数flag里
常用符号信息:
int (*errfunc) (const char *epath, int eerrno):
保存当前出错的路径和原因
glob_t *pglob: 将解析pattern的结果存放到glob_t指针指向的地址中去
(gl_pathc, *gl_pathv)和(argc, 、 argv)组合非常相近
(argc, 、 *argv)组合结构:
globfree函数:
opendir()
closedir()
readdir()
rewinddir()
seekdir()
telldir()
使用glob函数实现du命令功能
$:du
显示当前路径占的空间大小,默认以字节为单位显示
$:du filename
表示文件占的磁盘大小
$du filename1 filename2 ...
分别显示多个文件占的磁盘大小
思路:
1.如果du后面为空,则对当前目录进行操作;
2.如果du后面有路径信息,则对给定的路径进行解析。
路径分为两种,一种是非目录文件,一种是目录文件。
对于非目录文件,直接计算block
对于目录文件,把目录文件使用glob进行路径解析,使用递归计算
//FS/mydu.c
//避免回路,陷入递归死循环
static int pathnoloop(const char* path)
{
char *pos;
pos = strrchr(path, '/');
if(pos == NULL)
exit(1);
if(strcmp(pos+1, ".") == 0 || strcmp(pos+1, "..") == 0)
return 0;
return 1;
}
static int64_t mydu(const char* path)
{
//1.struct stat buf; 调整后,buf只在递归之前出现,则可以优化到静态区
static struct stat buf;
static char nextpath[PATHSIZE]; //只在递归前出现,可以优化
glob_t globres;
int i; //不可优化,跨递归
int64_t sum;
if(lstat(path, &buf) < 0)
{
perror("lstat()");
exit(1);
}
if(!S_ISDIR(buf.st_mode))
{
return buf.st_blocks;
}
// /aaa/bbb/ccc/ddd/eee/*
// /aaa/.*
strncpy(nextpath, path, PATHSIZE);
strncat(nextpath, "/*", PATHSIZE);
glob(nextpath, 0, NULL, &globres);
strncpy(nextpath, path, PATHSIZE);
strncat(nextpath, "/.*", PATHSIZE);
glob(nextpath, GLOB_APPEND, NULL, &globres);
//1.sum = 0;
sum = buf.st_blocks;
for(i = 0; i < globres.gl_pathc; i++)
{
if(pathnoloop(globres.gl_pathv[i]))
sum += mydu(globres.gl_pathv[i]);
}
//1.增加当前路径的大小
//sum += buf.st_blocks;
globfree(&globres);
return sum;
}
小结:
1.如何在栈不破裂的情况下,增加递归的层数?
压一个现场,需要压返回地址,局部变量,函数递归传递的参数
返回地址、参数不可省,局部变量可以通过其他方式减少。进而减少一个现场传递的内容,提高递归层数。
建议:
如果一个变量的使用单纯的在递归点之前(之后),则这个变量可以被优化到静态区存放。
如果一个变量的使用跨了递归区间,则不能优化;