Linux系统编程之目录解析

一、glob(),globfree()

1.glob()

glob()函数是一个用于模式匹配的函数,它可以根据指定的模式匹配文件路径。

         glob()函数的第一个参数是匹配模式,可以使用通配符来进行模式匹配。第二个参数是一个标志,用位图表示,可以设置为0。第三个参数是一个可选的错误处理函数,可以设置为nullptr。第四个参数是一个glob_t结构体,用于存储匹配结果。

        glob_t结构体的第一个成员gl_pathc是匹配到的路径的个数,第二个成员gl_pathv是匹配到的路径的字符串数组,以NULL结束,在某些情况下,glob()函数可能会在gl_pathv数组的开头插入一些额外的元素。gl_offs表示这些额外元素的数量。通常情况下,gl_offs的值为0。

下面是一些常用的flag参数:

  1. GLOB_ERR:如果发生错误(如无法访问目录或无法读取文件),则将设置GLOB_ERR标志,并且glob()函数将返回一个非零值。

  2. GLOB_APPEND:在结构体后面追加读取到的目录信息。

  3. GLOB_MARK:如果匹配的路径名是一个目录,则在路径名后面添加一个斜杠/

  4. GLOB_NOSORT:不对匹配的路径名进行排序。

  5. GLOB_NOESCAPE:禁用对通配符进行转义的特殊字符的处理。默认情况下,glob()函数会将\字符视为转义字符。

  6. GLOB_TILDE:在匹配时扩展波浪号~字符为用户的主目录路径

2.globfree()

globfree()用于释放glob_t结构体,参数只有一个glob_t结构体指针。

这是一个glob函数的使用示例,该代码将打印指定路径下的所有.txt文件。

#include <iostream>
#include <glob.h>

int main() {
    glob_t result;
    int status = glob("path/to/directory/*.txt", 0, nullptr, &result);
    
    if (status == 0) {
        for (size_t i = 0; i < result.gl_pathc; ++i) {
            std::cout << result.gl_pathv[i] << std::endl;
        }
    }
    
    globfree(&result);
    
    return 0;
}

二、目录流相关文件

1.opendir(),fdopendir()

opendir()函数用于打开一个目录,并返回一个指向DIR类型的指针,该指针可以用于后续的目录操作。fdopendir()则是用一个被open过的目录文件返回的文件描述符来打开一个目录。

 2.closedir()

closedir()函数用于关闭一个打开的文件流,并且会关闭其文件描述符。

 3.readdir()

readdir()函数用于读取目录中的文件和子目录。它接受一个指向DIR类型的指针作为参数,并返回一个指向dirent结构体的指针,该结构体包含了目录流中目录指针(dirp)所指向的下一个文件的信息。当没有文件可读时返回NULL。

 其中dirent结构体成员如下:

  1. ino_t d_ino:文件的inode号,用于唯一标识文件。

  2. off_t d_off:文件在目录中的偏移量。

  3. unsigned short d_reclendirent结构体的长度。

  4. unsigned char d_type:文件的类型。可以使用宏定义来判断文件类型,如DT_REG表示普通文件,DT_DIR表示目录等。

  5. char d_name[]:文件名。这是一个以null结尾的字符数组,存储了文件的名称。注意:此文件名为相对于所打开文件的相对文件名。

这是readdir读取目录文件的示例:

#include <iostream>
#include <dirent.h>

int main() {
    DIR* dir = opendir("path/to/directory");
    if (dir == nullptr) {
        std::cerr << "Failed to open directory." << std::endl;
        return 1;
    }
    
    dirent* entry;
    while ((entry = readdir(dir)) != nullptr) {
        std::cout << "Name: " << entry->d_name << ", Type: " << static_cast<int>(entry->d_type) << std::endl;
    }
    
    closedir(dir);
    
    return 0;
}

4.rewenddir(),seekdir(),telldir()

rewinddir()seekdir()telldir()都是用于在目录流中进行定位和操作的函数。

1)rewinddir()函数用于将目录流的位置重置到目录的开头。它没有参数,只需调用即可。

2)seekdir()函数用于将目录流的位置设置为指定的位置。它接受一个由telldir()返回的long类型的参数,表示要设置的位置。

3)telldir()函数用于获取目录流的当前位置。它返回一个long类型的值,表示当前位置。

三、mydu的实现

有了上面的函数,我们就可以自己写一个du命令(统计文件所占空间)了。

可以选择用glob()或是目录流,这里我使用的是目录流。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdint.h>
#include <errno.h>

#define PATHSIZE 1024

static int8_t is_noloop(char *path)
{
    char *pos = strrchr(path,'/');
    if(pos == NULL)
        pos = path-1;

    if(strcmp(".",pos+1)==0 || strcmp("..",pos+1)==0)
        return 0;
    else
        return 1;
}

uint64_t Mydu(char *path)
{
    struct stat st;
    if(lstat(path,&st) != 0)
    {
        perror("lstat");
        exit(1);
    }

    if(S_ISDIR(st.st_mode) == 0)
    {
        return (st.st_blocks)/2;
    }
    else
    {
        DIR *dir = opendir(path);
        struct dirent *dr;
        uint64_t sum = st.st_blocks/2;
        while((dr=readdir(dir)) != NULL)
        {
            char npath[PATHSIZE] = {'\0'};
            strcpy(npath,path);
            strcat(npath,"/");
            strcat(npath,dr->d_name);

            if(is_noloop(npath))
            {
                sum += Mydu(npath);
            }
        }

        closedir(dir);

        if(errno != 0)
        {
            perror("readdir():");
            exit(1);
        }

        return sum;
    }
}

int main(int argc,char **argv)
{
    if(argc != 2)
    {
        fprintf(stderr,"Usage:./mydu dirname\n");
        return -1;
    }

    printf("%lu\n",Mydu(argv[1]));

    return 0;
}

上面是du命令,下面是我们写的mydu.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值