【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.mzph.cn/news/94648.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySql运维篇---008:日志:错误日志、二进制日志、查询日志、慢查询日志,主从复制:概述 虚拟机更改ip注意事项、原理、搭建步骤

1. 日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 该日志是默认开启的&a…

Scala第十七章节

Scala第十七章节 scala总目录 文档资料下载 章节目标 了解集合的相关概念掌握Traversable集合的用法掌握随机学生序列案例 1. 集合 1.1 概述 但凡了解过编程的人都知道程序 算法 数据结构这句话, 它是由著名的瑞士计算机科学家尼古拉斯沃斯提出来的, 而他也是1984年图灵…

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

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

第四十六章 命名空间和数据库 - 系统提供的数据库

文章目录 第四十六章 命名空间和数据库 - 系统提供的数据库系统提供的数据库ENSLIBIRISAUDITIRISLIBIRISLOCALDATAIRISSYS (the system manager’s database 系统管理器的数据库)IRISTEMP 第四十六章 命名空间和数据库 - 系统提供的数据库 系统提供的数据库 IRIS 提供以下数据…

使用华为eNSP组网试验⑷-OSPF多区域组网

今天进行了OSPF的多区域组网试验&#xff0c;本来这是个很简单的操作&#xff0c;折腾了好长时间&#xff0c;根本原因只是看了别人写的配置代码&#xff0c;没有真正弄明白里面对应的规则。 一般情况下&#xff0c;很多单位都使用OSPF进行多区域的组网&#xff0c;大体分为1个…

CUDA C编程权威指南:1-基于CUDA的异构并行计算

什么是CUDA&#xff1f;CUDA&#xff08;Compute Unified Device Architecture,统一计算设备架构&#xff09;是NVIDIA&#xff08;英伟达&#xff09;提出的并行计算架构&#xff0c;结合了CPU和GPU的优点&#xff0c;主要用来处理密集型及并行计算。什么是异构计算&#xff1…

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

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

mysql主从复制和读写分离

在企业应用中&#xff0c;成熟的业务通常数据量都比较大 单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求 配置多台主从数据库服务器以实现读写分离 所以要做主从服务器&#xff0c;保证安全性 做一写一读服务器&#xff0c;将提升性能 1、什么是读写分离 …

Redis Cluster Gossip Protocol: PING, PONG, MEET

返回目录 PING / PONG / MEET 的发送 过程 计算freshNodes。freshNodes表示在消息中能携带的&#xff0c;在cluster节点字典中的节点总数&#xff0c;但需要减去myself和对端节点&#xff0c;因为myself的信息会存储在消息头中。实际上&#xff0c;并非所有在cluster节点字典…

IPv4 、IPv6

以下是一个简单的表格&#xff0c;用于比较IPv4和IPv6的主要区别&#xff1a; 特性IPv4IPv6地址表示32位二进制数&#xff0c;点分十进制表示128位二进制数&#xff0c;冒号分隔的16进制表示地址长度32位&#xff08;约42亿个可能的地址&#xff09;128位&#xff08;几乎无限…

C语言中的异常处理机制是什么?

C语言中的异常处理机制 C语言是一门强大而灵活的编程语言&#xff0c;它为程序员提供了广泛的控制权和自由度。然而&#xff0c;C语言本身并不提供像其他高级语言一样的内置异常处理机制&#xff0c;如Java中的try-catch或Python中的异常处理。因此&#xff0c;C语言程序员需要…

中间件中使用到的设计模式

本文记录阅读源码的过程中&#xff0c;了解/学习到中间件使用到的设计模式及具体运用的组件/功能点 1. 策略模式 1. Nacos2.x中grpc处理时通过请求type来进行具体Handler映射&#xff0c;找到对应处理器。 2. 模板模式 1. Nacos配置数据读取&#xff0c;内部数据源、外部数据…

隐私交易成新刚需,Unijoin 凭什么优势杀出重围?

随着区块链技术的普及和发展&#xff0c;全球加密货币用户在持续增长&#xff0c;根据火币研究院公布的数据&#xff0c;2022年全球加密用户已达到 3.2亿人&#xff0c;目前全球人口总数超过了 80亿&#xff0c;加密货币用户渗透率已达到了 4%。 尤其是在 2020 年开启的 DeFi 牛…

如何像人类一样写HTML之图像标签,超链接标签与多媒体标签

文章目录 前言一、图像标签1.1 什么是图像标签&#xff1f;2.2 如何使用图像标签&#xff1f; 二、超链接标签2.1 什么是超链接标签&#xff1f;2.2 如何使用超链接标签&#xff1f; 三、多媒体标签3.1 什么是多媒体标签&#xff1f;3.2 如何使用多媒体audio标签&#xff1f;3.…

Python入门教程 | Python 常用标准库概览

Python3 标准库概览 Python 标准库非常庞大&#xff0c;所提供的组件涉及范围十分广泛&#xff0c;使用标准库我们可以让您轻松地完成各种任务。 以下是一些 Python3 标准库中的模块&#xff1a; os 模块&#xff1a;os 模块提供了许多与操作系统交互的函数&#xff0c;例如创…

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(UDP/TCP)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf2.2.1 安装2.2.2 工具 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子: awesome.proto4.1.1 加载.proto文件方式4.1.2 加载.json文件方式4.1.3 加载.js文件方式 4.2 例…

多线程 - 单例模式

单例模式 ~~ 单例模式是常见的设计模式之一 什么是设计模式 你知道象棋,五子棋,围棋吗?如果,你想下好围棋,你就不得不了解一个东西,”棋谱”,设计模式好比围棋中的 “棋谱”. 在棋谱里面,大佬们,把一些常见的对局场景,都给推演出来了,照着棋谱来下棋,基本上棋力就不会差到哪…

TAADpapers的工具包用到的lru是lru-dict

TAADpapers的工具包用到的lru是lru-dict 运行时提示&#xff1a;no model named lru 安装lru时报错详情&#xff1a; (textattack-master) G:\xxx\TextAttack-master>pip install lru Collecting lruUsing cached lru-0.1.tar.gz (1.1 kB)Preparing metadata (setup.py) ..…

docker-compose一键启动neo4j

下载镜像 docker pull neo4j:3.5.22-community 编写配置文件 参考文档 编写docker-compose.yml文件 version: "3"services:neo4j:image: neo4j:3.5.22-communitycontainer_name: neo4j restart: alwaysports:- 7474:7474- 7687:7687environment:- NEO4J_AUTH:ne…

Scala第十五章节

Scala第十五章节 1. 递归 2. 案例一: 求阶乘 3. 案例二: 斐波那契数列 4. 案例三: 打印目录文件 scala总目录 文档资料下载