网站建设销售合作合同范本,负责加强局网站建设,tag 网站备案,济南网站优化分析一、du命令解析 Summarize disk usage of the set of FILEs, recursively for directories. du 命令用于输出文件所占用的磁盘空间 默认情况下#xff0c;它会输出当前目录下#xff08;包括该目录的所有子目录下#xff09;的所有文件的大小总和#xff0c;以 1024B 为单…一、du命令解析 Summarize disk usage of the set of FILEs, recursively for directories. du 命令用于输出文件所占用的磁盘空间 默认情况下它会输出当前目录下包括该目录的所有子目录下的所有文件的大小总和以 1024B 为单位 也可指定路径。若指定的路径为目录 则输出该目录下所有文件大小的总和若指定的路径为文件则输出该文件大小。均以 1024B 为单位 二、类 du 命令实现
我们希望实现一个命令该命令能够按照如下使用方式使用统计 path 所占的磁盘空间以1024B为单位
mydu path
2.1 如果 path 为普通文件
先考虑实现输出普通文件大小的功能
#include stdio.h
#include stdlib.h
#include sys/types.h
#include unistd.h
#include sys/stat.hstatic int64_t mydu(const char *path) {struct stat statbuf;if (lstat(path, statbuf) 0) {perror(lstat());exit(1);}if (!S_ISDIR(statbuf.st_mode)) // 如果为普通文件return statbuf.st_blocks / 2; // 为什么要除以2// 因为stat结构体中的st_blocks成员统计的是文件占了多少个大小为512B的块// 而du统计的单位为1024B因此需要除以2
}int main(int argc, char * argv[]) {if (argc 2) {fprintf(stderr, Usage: %s pathname\n, argv[0]);exit(1);}printf(%ld\n, mydu(argv[1]));exit(0);
} 2.2 如果 path 为目录
再考虑实现输出目录下所有文件大小之和的功能
#include stdio.h
#include stdlib.h
#include sys/types.h
#include unistd.h
#include sys/stat.h
#include glob.h
#include string.h
#define PATHSIZE 1024static int path_noloop(const char *path) { // 避免无限递归char * pos strrchr(path, /);if (pos NULL)exit(1);if (strcmp(pos 1, .) 0 || strcmp(pos1, ..) 0)return 0;return 1;}static int64_t mydu(const char *path) {struct stat statbuf;if (lstat(path, statbuf) 0) {perror(lstat());exit(1);}if (!S_ISDIR(statbuf.st_mode))return statbuf.st_blocks; // 当path为普通文件不用后续递归了//// 下面情况考虑path为目录//char nextpath[PATHSIZE];glob_t globbuf;strncpy(nextpath, path, PATHSIZE);strncat(nextpath, /*, PATHSIZE); // 将path名拓展为/dir/*glob(nextpath, 0, NULL, globbuf); // 解析该path目录下的所有非隐藏名字strncpy(nextpath, path, PATHSIZE); strncat(nextpath, /.*, PATHSIZE); // 将path名拓展为/dir/.*glob(nextpath, GLOB_APPEND, NULL, globbuf); // 解析该path目录下的所有隐藏名字并添加到已解析的名字集int64_t sum 0;for (int i 0; i globbuf.gl_pathc; i) {if (path_noloop(globbuf.gl_pathv[i]))sum mydu(globbuf.gl_pathv[i]); // 递归获取某个名字下的文件大小可以通过该函数本身实现}globfree(globbuf);return sum;}int main(int argc, char * argv[]) {if (argc 2) {fprintf(stderr, Usage: %s pathname\n, argv[0]);exit(1);}printf(%ld\n, mydu(argv[1])/2); // 打印的时候才除以2避免递归过程中除多了exit(0);
} 对比验证针对目录统计出来的结果与命令 du 相同
tail -1 指的仅输出最后一行 补充
1、程序中 path_noloop 是干什么用的
先想想我们处理 path 为目录时的递归思路 解析某一个目录下的名字可以通过调用递归函数本身实现用分解问题的思想遍历树看似没啥问题
但是有一点需要注意某个目录下的名字包含其自身和上一级菜单
也就是如果我们不注意这一点遍历树的过程就会像下面这样 所以需要通过下面的函数判断 path 是不是以 . 或者 .. 结尾的即是否指向路径所表示的目录本身或上一级如果是则不从这条路进入递归
static int path_noloop(const char *path) { // 避免无限递归char * pos strrchr(path, /);if (pos NULL)exit(1);if (strcmp(pos 1, .) 0 || strcmp(pos1, ..) 0)return 0;return 1;}
2、代码有办法优化吗
有办法。因为递归调用需要频繁利用栈空间而进程允许的栈空间大小是有上限的可通过命令 ulimit -a 查看。我们可以将某些栈空间的数据放在全局区静态区 节约栈空间
原则如果一个变量的使用仅在递归点之前则该变量可以放在静态区存放
优化代码如下
#include stdio.h
#include stdlib.h
#include sys/types.h
#include unistd.h
#include sys/stat.h
#include glob.h
#include string.h
#define PATHSIZE 1024static int path_noloop(const char *path) { // 避免无限递归char * pos strrchr(path, /);if (pos NULL)exit(1);if (strcmp(pos 1, .) 0 || strcmp(pos1, ..) 0)return 0;return 1;}static int64_t mydu(const char *path) {static struct stat statbuf;if (lstat(path, statbuf) 0) {perror(lstat());exit(1);}if (!S_ISDIR(statbuf.st_mode))return statbuf.st_blocks; // 当path为普通文件不用后续递归了//// 下面情况考虑path为目录//static char nextpath[PATHSIZE];glob_t globbuf;strncpy(nextpath, path, PATHSIZE);strncat(nextpath, /*, PATHSIZE); // 将path名拓展为/dir/*glob(nextpath, 0, NULL, globbuf); // 解析该path目录下的所有非隐藏名字strncpy(nextpath, path, PATHSIZE); strncat(nextpath, /.*, PATHSIZE); // 将path名拓展为/dir/.*glob(nextpath, GLOB_APPEND, NULL, globbuf); // 解析该path目录下的所有隐藏名字并添加到已解析的名字集int64_t sum 0;for (int i 0; i globbuf.gl_pathc; i) {if (path_noloop(globbuf.gl_pathv[i]))sum mydu(globbuf.gl_pathv[i]); // 递归获取某个名字下的文件大小可以通过该函数本身实现}globfree(globbuf);return sum;}int main(int argc, char * argv[]) {if (argc 2) {fprintf(stderr, Usage: %s pathname\n, argv[0]);exit(1);}printf(%ld\n, mydu(argv[1])/2); // 打印的时候才除以2避免递归过程中除多了exit(0);
} 哒咩哒咩哒咩哒咩哒咩哒咩~~~~