【APUE】文件系统 — 类 du 命令功能实现

一、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.h>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 / 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(pos+1, "..") == 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(pos+1, "..") == 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(pos+1, "..") == 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);
}

 

哒咩哒咩哒咩哒咩哒咩哒咩~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/148826.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的餐厅点菜管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

NXP公司K60N512+PWM控制BLDC电机

本篇文章介绍了使用NXP公司提供的塔式快速原型系统来驱动控制带霍尔传感器的无刷直流电机。文章涉及的塔式快速原型系统主要包括以下四个独立板卡&#xff1a;1.塔式系统支撑模块&#xff08;TWR-Elevator&#xff09;&#xff0c;用以连接微控制器以及周边模块&#xff1b;2.低…

ChatGPT必应联网功能正式上线

今日凌晨发现&#xff0c;ChatGPT又支持必应联网了&#xff01;虽然有人使用过newbing这个阉割版的联网GPT4&#xff0c;但官方版本确实更加便捷好用啊&#xff01; 尽管 ChatGPT 此前已经展现出了其他人工智能模型无可比拟的智能&#xff0c;但由于其训练数据的限制&#xff…

CUDA+cuDNN+TensorRT 配置避坑指南

深度学习模型加速部署的环境配置&#xff0c;需要在本地安装NVIDIA的一些工具链和软件包&#xff0c;这是一个些许繁琐的过程&#xff0c;而且一步错&#xff0c;步步错。笔者将会根据自己的经验来提供建议&#xff0c;减少踩坑几率。当然可以完全按照官方教程操作&#xff0c;…

xilinx的原语的使用

xilinx的原语的使用 在学习FPGA实现千兆网时需要GMII转RGMII&#xff0c;这就涉及了原语的使用&#xff0c;特此记录&#xff01; 一、原语 与RGMII接口相关的原语&#xff1a; BUFG:全局时钟网络 BUFIO&#xff1a;只能采集IO的数据&#xff0c;采集IO数据的时候延时是最低的…

Ubantu 20.04 卸载与安装 MySQL 5.7 详细教程

文章目录 卸载 MySQL安装 MySQL 5.71.获取安装包2.解压并安装依赖包3.安装 MySQL4.启动 MySQL 扩展开启 gtid 与 binlog 卸载 MySQL 执行以下命令即可一键卸载&#xff0c;包括配置文件目录等。 # 安装sudo软件 apt-get install sudo -y # 卸载所有以"mysql-"开头的…

Raspberry Pi 5 新平台 新芯片组

Raspberry Pi 5 的 CPU 和 GPU 性能提高了两到三倍&#xff1b;内存和 I/O 带宽大约是两倍&#xff1b;并且是首款采用英国剑桥内部设计的芯片的 Raspberry Pi 计算机&#xff0c;4GB 型号的售价为 60 美元&#xff0c;8GB 版本的售价为 80 美元 主要特点包括&#xff1a; 2.4…

[架构之路-229]:计算机体硬件与系结构 - 计算机系统的矩阵知识体系结构

目录 一、纵向&#xff1a;目标系统的分层结构 1.1 目标系统的架构 1.2 网络协议栈 1.3 计算机程序语言分层 二、横向&#xff08;构建目标系统的时间、开发阶段&#xff09;&#xff1a;软件工程 三、二维矩阵知识体系结构 一、纵向&#xff1a;目标系统的分层结构 1.1…

关于字符拼接

当然&#xff0c;以下是加入了幽默注释的代码和对应的逻辑树&#xff1a; # 提示用户输入input和txt内容&#xff0c;期待用户真有输入 input_text input("请输入input文本&#xff1a;") # 好了&#xff0c;快点输入吧 txt_text input("请输入txt文本&#…

软件工程第四周

模型建立的基本理念 模型是对现实世界复杂系统的简化和抽象&#xff0c;目的是为了更好地理解、分析和预测系统的行为。它能够真实反映研究对象的整体结构 or 某一侧面&#xff08;功能、反应&#xff09;的本质特征和变化规律。可以建立不同的子模型用于反应系统不同的侧面。同…

DP读书:《openEuler操作系统》(四)鲲鹏处理器

鲲鹏处理器 一、处理器概述1.Soc2.Chip3.DIE4.Cluster5.Core 二、体系架构1.计算子系统2.存储子系统3.其他子系统 三、CPU编程模型1.中断与异常2.异常级别a.基本概念b.异常级别切换 下面为整理的内容&#xff1a;鲲鹏处理器 架构与编程&#xff08;一&#xff09;处理器与服务器…

Leetcode290. 单词规律

给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 解题思路&#xff1a;哈希 力扣&#xff08;LeetCode&…

MIT 6.S081学习笔记(第二章)

〇、前言 本文主要完成MIT 6.S081 实验二&#xff1a;system call 一、Using gdb (easy) Question requirements In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspe…

【C++】运算符重载 ⑤ ( 一元运算符重载 | 使用 成员函数 实现 前置 ++ 自增运算符重载 | 使用 成员函数 实现 前置 - - 自减运算符重载 )

文章目录 一、一元运算符重载1、使用 成员函数 实现 前置 自增运算符重载2、使用 成员函数 实现 前置 - - 自减运算符重载 二、完整代码示例 一、一元运算符重载 1、使用 成员函数 实现 前置 自增运算符重载 使用 全局函数 实现 前置 自增运算符重载 : 首先 , 写出函数名 ,…

Java数据结构————优先级队列(堆)

一 、 优先级队列 有些情况下&#xff0c;操作的数据可能带有优先级&#xff0c; 一般出队列时&#xff0c;可能需要优先级高的元素先出队列。 数据结构应该提供两个最基本的操作&#xff0c; 一个是返回最高优先级对象&#xff0c; 一个是添加新的对象。 这种数据结构就是优…

[架构之路-228]:计算机硬件与体系结构 - 硬盘存储结构原理:如何表征0和1,即如何存储0和1,如何读数据,如何写数据(修改数据)

目录 前言&#xff1a; 一、磁盘的盘面组成 1.1 磁盘是什么 ​编辑1.2 磁盘存储介质 1.3 磁盘数据的组织 1.3.1 分层组织&#xff1a;盘面号 1.3.2 扇区和磁道 1.3.3 数据 1.3.4 磁盘数据0和1的存储方式 1.3.5 磁盘数据0和1的修正方法 1.3.6 磁盘数据0和1的读 二、…

(四)正点原子STM32MP135移植——u-boot移植

一、概述 u-boot概述就不概述了&#xff0c;u-boot、kernel、dtb三件套&#xff0c;dddd 经过国庆艰苦奋战&#xff0c;已经成功把所有功能移植好了 二、编译官方代码 进入u-boot的目录 2.1 解压源码、打补丁 /* 解压源码 */ tar xf u-boot-stm32mp-v2022.10-stm32mp-r1-r0.…

mysql双主双从读写分离

架构图&#xff1a; 详细内容参考&#xff1a; 结果展示&#xff1a; 178.119.30.16&#xff08;从&#xff09;- master 178.119.30.17&#xff08;从&#xff09;- slave 由上述结果可以看出&#xff0c;产生了主备节点同时抢占VIP的问题&#xff08;即脑裂问题&#xff09…

React18入门(第二篇)——React18+Ts项目配置husky、eslint、pretttier、commitLint

前言 我的项目版本如下&#xff1a; React&#xff1a; V18.2.0Node.js: V16.14.0TypeScript&#xff1a;最新版工具&#xff1a; VsCode 本文将采用图文详解的方式&#xff0c;手把手带你快速完成在React项目中配置husky、prettier、commitLint&#xff0c;实现编码规范的统…

nodejs+vue养老人员活体鉴权服务系统elementui

系统 统计数据&#xff1a;统计报表、人员台账、机构数据、上报数据、核验报表等&#xff0c;养老人员活体鉴权服务是目前国家养老人员管理的重要环节&#xff0c;主要为以养老机构中养老人员信息为基础&#xff0c;每月进行活体鉴权识别并统计数据为养老补助等管理。前端功能&…