10目录检索原理与应用

目录检索原理与应用

之前设计的程序只能访问某个路径下的某个文件,如果打算一次访问某个路径下的多个不同类型的文件,就需要用户手动调用open函数实现,但是当文件数量较多时,这种方案并不能满足需求,那请问是否有比较轻松高效的方式来实现访问某个路径下的多个不同类型的文件呢?

当然是有的,在Linux系统下一切皆文件,目录在Linux系统下也属于文件类型之一,可以通过系统IO来进行访问,常见的访问目录的接口有:opendir、readdir、chdir、mkdir、rmdir、remove、getcwd、rewindir等。

一、基本概念

在Linux系统下目录是一种特殊的文件,只不过目录存储的数据的最小单位并不是字符,而是目录项,所以目录与普通文件又有所区别,另外,Linux文件系统下目录和文件夹的含义也并不相同,目录的本质是索引,文件夹的本质是容器

也就是说,目录是用来保存项目的索引,而不用保存项目本身。Linux 和 UNIX 中的目录并不保存它里面的文件。它们只是记录文件位置的信息。

举个例子:目录和文件夹的区别就相当于门牌号和房子的区别,房子里面可以住人或者存放物品,而门牌号只是记录房子所在的位置,方便用户寻找和访问。

img

可以看到,在 Linux 或 Unix 操作系统中所有的文件和目录都被组织成以一个根节点开始的倒置的树状结构。

Linux系统的文件系统的最顶层是由根目录开始的,使用 / 来表示根目录。在根目录之下的既可以是目录,也可以是文件,而每一个目录中又可以包含子目录文件。如此反复就可以构成一个庞大的文件系统。

二、磁盘结构

如果Linux系统的目录并不存储文件的实际数据内容,而是存储目录项,那请问文件实际的内容存储在哪里?目录的目录项又是什么东西?

文件数据是储存在磁盘上的,磁盘一般就是指计算机的硬盘,硬盘存储数据的最小存储单位叫做扇区。一般计算机每个扇区(Sector)存储512字节,而连续的8个扇区组成了一个数据块(Block),大小为4KB

计算机一般是以数据块(Block)为单位访问数据,因为这样可以提高CPU的访问效率,而文件数据都存储在数据块中,所以为了能够方便找到数据块中存储数据的位置,就必须找到一个地方存储文件的属性(比如文件的字节数、文件的读写权限、文件的时间戳等),这种存储文件属性信息的区域叫做inode,中文翻译为索引节点,在Linux系统下inode其实是以结构体的形式来存储文件信息的,可以通过man手册的第7章了解inode,如 man 7 inode。

image-20260127174117327

所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区(block),存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。inode区是以数组的形式存储的,数组下标就是inode编号,每个元素就是一个结构体,inode结构体中会有一个指针指向block区,也就是指向存放文件内容的数据块。

img

既然Linux的文件系统中的每个文件都有一个inode,并且每个inode都有编号,请问应该如何查看文件的inode的编号?

可以直接通过shell命令: ls,有2个选项: -l 显示详细信息 -i 打印文件的索引

img

三、接口说明

3.1创建目录

Linux系统提供了一个用于创建目录的mkdir函数接口,第一个参数pathname指的是目录的路径,第二个参数mode用来指定新目录的模式。

image-20260127174402758

3.2删除目录

Linux系统提供了一个用于删除空目录rmdir函数接口,第一个参数pathname指的是待删除目录的路径。

image-20260127174437374

3.3 打开目录

Linux系统提供了一个用于打开目录的opendir函数接口,第一个参数pathname指的是待打开目录的路径。

image-20260127174546070

3.4 进入目录

另外,打开目录并不意味着进入目录,而获取目录里面的文件的信息必须要先进入目录,可以用函数 chdir() 进入目录。

image-20260127174628325

3.5 读取目录

Linux系统提供了一个用于读取目录的readdir函数接口,第一个参数dirp指的是待读取目录的目录指针。函数成功返回一个指向该目录中下一个目录项的指针,失败返回NULL。

image-20260127174740655

函数读取成功,drip指向下一个目录项的指针,失败返回NULL。

image-20260127174900871

练习:设计程序,利用操作目录的函数接口实现读取某个路径下的目录并把该目录下的规则文件的名称输出到终端。并且要求目录路径作为main函数参数的形式传递。

//要求:把指定路径下的规则文件的文件名称输出到终端
int main(int argc, char const *argv[])
{
	
	//1.检查参数有效性
	if (2 != argc)
	{
		printf("argument is invaild!\n");
		return -1;
	}

	//2.打开指定目录 opendir  错误处理  
	DIR * dir = opendir(argv[1]);

	//3.循环读取目录中的目录项,当readdir的返回值是NULL则终止循环
	while(1)
	{
		struct dirent * pdir = readdir(dir);

		if(NULL == pdir)
		{
			break;
		}

		//如果文件不是规则文件,则跳过
		if (pdir->d_type != DT_REG || pdir->d_name[0] == '.')
		{
			continue;
		}
		
		//输出每个目录项中记录的磁盘中规则文件的名称
		printf("file name is [%s]\n",pdir->d_name); 
	}
	
	

	return 0;
}

如果某个目录下存储3个普通文件和1个文件夹,但是程序输出结果并不能区分出来文件的类型,请问应该如何解决该问题?

如果想要区分磁盘中的文件类型,第一个方案是可以利用readdir函数返回的目录项中的成员,另一个方案则是利用stat函数获取文件的信息

3.6文件属性

Linux系统提供了一个用于获取文件信息的stat函数接口,第一个参数path指的是待读取文件的路径,第二个参数指的是获取的文件信息结构体的地址。

image-20260127180823747

image-20260127180858514

image-20260127180921928

在结构体 stat 中文件的类型和权限并没有分开存储,而被统一存储到同一个成员 st_mode中。

img

image-20260127181413291

image-20260127181705462

因为这类文件类型检测非常常见,POSIX 标准定义了额外的宏,让我们可以更简洁地通过 st_mode 来判断文件

image-20260127181712547

stat(pathname, &sb);
if (S_ISREG(sb.st_mode)) {
    /* 处理普通文件 */
}
posted @ 2026-01-27 18:20  郭小胖  阅读(0)  评论(0)    收藏  举报