一、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参数:
-
GLOB_ERR
:如果发生错误(如无法访问目录或无法读取文件),则将设置GLOB_ERR
标志,并且glob()
函数将返回一个非零值。 -
GLOB_APPEND
:在结构体后面追加读取到的目录信息。 -
GLOB_MARK
:如果匹配的路径名是一个目录,则在路径名后面添加一个斜杠/
。 -
GLOB_NOSORT
:不对匹配的路径名进行排序。 -
GLOB_NOESCAPE
:禁用对通配符进行转义的特殊字符的处理。默认情况下,glob()
函数会将\
字符视为转义字符。 -
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结构体成员如下:
-
ino_t d_ino
:文件的inode号,用于唯一标识文件。 -
off_t d_off
:文件在目录中的偏移量。 -
unsigned short d_reclen
:dirent
结构体的长度。 -
unsigned char d_type
:文件的类型。可以使用宏定义来判断文件类型,如DT_REG
表示普通文件,DT_DIR
表示目录等。 -
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.