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

这篇具有很好参考价值的文章主要介绍了【APUE】文件系统 — 类 du 命令功能实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、du命令解析

二、类 du 命令实现

2.1 如果 path 为普通文件

2.2 如果 path 为目录 

补充 


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

【APUE】文件系统 — 类 du 命令功能实现,UNIX环境高级编程,linux,运维,服务器

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 1024

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;

}

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

【APUE】文件系统 — 类 du 命令功能实现,UNIX环境高级编程,linux,运维,服务器

对比验证,针对目录统计出来的结果与命令 du 相同

tail -1 指的仅输出最后一行


补充 

  • 1、程序中 path_noloop 是干什么用的?

先想想我们处理 path 为目录时的递归思路:

【APUE】文件系统 — 类 du 命令功能实现,UNIX环境高级编程,linux,运维,服务器

解析某一个目录下的名字可以通过调用递归函数本身实现,用分解问题的思想遍历树,看似没啥问题

但是有一点需要注意:某个目录下的名字包含其自身和上一级菜单!

也就是如果我们不注意这一点,遍历树的过程就会像下面这样: 

【APUE】文件系统 — 类 du 命令功能实现,UNIX环境高级编程,linux,运维,服务器

所以,需要通过下面的函数,判断 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 1024

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;

}

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

哒咩哒咩哒咩哒咩哒咩哒咩~~~~文章来源地址https://www.toymoban.com/news/detail-728779.html

到了这里,关于【APUE】文件系统 — 类 du 命令功能实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux基础命令-du查看文件的大小

    du 命令介绍 语法格式 基本参数 参考实例 1)以人类可读形式显示指定的文件大小 2)显示当前目录下所有文件大小 3)只显示目录的大小 4)显示根下哪个目录文件最大 5)显示所有文件的大小 6)只显示目录下的文件,不显示目录下的子目录 ll -h与du -h命令的区别  命令总结

    2024年02月08日
    浏览(45)
  • linux du命令解析(递归计算文件子目录大小)(计算大小)(计算容量)

    du 命令用于查看文件或目录的磁盘使用情况。它会递归地计算指定目录下所有文件和子目录的大小,并以可读性较好的方式显示出来。 用法 常用选项 -h :以人类可读的方式显示文件大小。 -s :仅显示总计大小,不显示每个文件和目录的详细信息。 -c :同时显示总计大小。

    2024年02月05日
    浏览(41)
  • [apue] 进程环境那些事儿

    众所周知,main 函数为 unix like 系统上可执行文件的\\\"入口\\\",然而这个入口并不是指链接器设置的程序起始地址,后者通常是一个启动例程,它从内核取得命令行参数和环境变量值后,为调用 main 函数做好安排。main 函数原型为: 这是 ISO C 和 POSIX.1 指义的,当然还存在下面几种

    2024年02月11日
    浏览(45)
  • 在windows系统环境下使用 tail 命令实时查看文件

    文章目录 前言 一、使用tail for Windows工具 二、使用Git Bash Linux系统下我们可以使用tail -f 命令实时查看文件,下面提供两种在windows系统环境下使用tail 命令的方法 。 tail for Windows 是便携式软件不需要安装,它可用于显示文件的最后一行并跟踪/监视文件的更改。 下载地址: 点

    2024年02月16日
    浏览(54)
  • 文件系统考古:1974-Unix V7 File System

    有时,进步难以察觉,特别是当你正身处其中时。而对比新旧资料之间的差异,寻找那些推动变革的信息源,我们就可以清晰地看到进步的发生。在Linux(以及大部分Unix系统)中,都可以印证这一点。 Unix V7 是 Unix 操作系统的一个重要的早期版本,于 1979 年发布,是贝尔实验

    2024年02月06日
    浏览(28)
  • APUE-文件I/O

    库函数调用 系统调用 在所有的ANSI C编译器中,C库函数都是相同的 各个操作系统的系统调用是不同的,这导致程序不可移植 它调用库函数中的一段程序(或函数) 它调用系统内核的服务 与用户程序相联系 在内核地址空间执行 它的运行时间属于“用户时间” 运行时间属于“

    2024年02月02日
    浏览(25)
  • Liunx 磁盘空间 df & du 命令详解

    显示磁盘的相关信息 df命令 用于显示磁盘分区上的可使用的磁盘空间。默认显示单位为KB。可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息。 语法 选项 参数 文件:指定文件系统上的文件。 大小格式 显示值以 --block-size 和 DF_BLOCK_SIZE , BLOCK_SIZE 和

    2024年02月04日
    浏览(35)
  • x-cmd pkg | trash-cli - 类 Unix 系统的命令行垃圾桶

    trash-cli 是类 Unix 系统的命令行垃圾桶,用于移动文件到回收站,同时会记录文件的原地址和删除日期。 该工具使用与 GNOME、KDE ​​和 XFCE 等桌面环境相同的垃圾桶,所以即使是非 GUI 系统,也可以满足以下使用垃圾桶的需求: 删除文件:使用 trash-put 命令将文件移动到 $HO

    2024年01月17日
    浏览(49)
  • 最全的李慧芹APUE-文件IO笔记

    注 : 李慧芹老师的视频课程请点这里, 本篇为系统IO一章的笔记, 课上提到过的内容基本都会包含, 上一章为标准IO 文件描述符( fd )是在文件IO中贯穿始终的类型 文件IO操作: open , close , read , write , lseek 文件IO与标准IO的区别 IO的效率问题 文件共享问题 原子操作 程序中的重定向

    2024年02月08日
    浏览(25)
  • HP-UX下du命令使用技巧

    本人习惯了Linux环境的du命令,在HP-UX下,发现du命令真的非常难用,有种让人很难受的感觉。主要是因为HP-UX下的du命令参数比Linux平台du命令参数要少很多,尤其是没有-h这个参数,它只能以kb形式显示文件/文件夹的大小,对于我来说,看起来非常不直观。下面是工作中,HP-

    2023年04月27日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包