文件描述符fd
通过对open函数的学习,我们知道了文件描述符就是一个小整数,可以再次用代码验证一下。
用系统调用函数open打开了四个文件,然后打印他们的文件描述符fd:
1 #include <stdio.h>
2 #include <sys/types.h>
3 #include <sys/stat.h>
4 #include <fcntl.h>
5 int main ()
6 {
7 int fd0 = open("./log.txt",O_WRONLY|O_CREAT,0644);
8 int fd1 = open("./log.txt",O_WRONLY|O_CREAT,0644);
9 int fd2 = open("./log.txt",O_WRONLY|O_CREAT,0644);
10 int fd3 = open("./log.txt",O_WRONLY|O_CREAT,0644);
11 ---
12 printf("fd0:%d\n",fd0);
13 printf("fd1:%d\n",fd1);
14 printf("fd2:%d\n",fd2);
15 printf("fd3:%d\n",fd3);
16 ---
17 close(fd0);
18 close(fd1);
19 close(fd2);
20 close(fd3);
21 return 0;
22 }
观察结果,我们很清楚的发现,这四个文件的文件描述符是从3开始的连续的小整数。那么为什么是从3开始,而不是0或者1呢? 0,1,2去哪里了呢?
0 & 1 & 2
- 在Linux进程中,默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2。
- 0,1,2对应的物理设备一般是:键盘,显示器,显示器。所以输输入输出还可以像下面这样:
1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <sys/types.h>
4 #include <string.h>
5
6 int main()
7 {
8 char buf[1024];
9 ssize_t s=read(0,buf,sizeof(buf));//从键盘读数据存入buf
10 if(s>0) {
11 buf[s]=0;
12 write(1,buf,strlen(buf));//将buf的数据显示在显示器上
13 write(2,buf,strlen(buf));//将buf的数据显示在显示器上
14 }
15 return 0;
16 }
这些数字对于我们来说很熟悉,很像是数组的下标。
一个进程要被管理起来就要有一个PCB,那么一个进程也可能打开多个文件,这就意味着在操作系统中也可能已经打开的文件比进程数还要多。操作系统肯定也是要把这些已经打开的文件管理起来。怎么管理呢?遵循原则还是先描述后管理。
在进程中,当我们每打开一个文件时,操作系统都会创建相应的数据结构描述目标文件,于是就产生了我们描述文件的file结构体(每打开一个文件都会创建一个描述该文件的结构体),表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数
组,每个元素都是一个指向打开文件的指针!
所以每次打开一个文件,把这个文件的地址赋给该指针数组中没有被使用的元素中就可以了。所以,当我们想标识这个文件的时候,只需要拿到该文件在数组里对应的下标就可以了就能完成相应的文件操作。
所以本质上,文件描述符就是这个指针数组的下标,只要拿着文件描述符就能找到对应的文件。可以借助我画的图理解一下
文件描述符的分配规则:
现在我们知道了每一个打开的文件都有一个文件描述符,那么他们的分配规则是什么呢?
在files_struct的指针数组中,找到当前没有被使用的最小的一个下标,就作为新的文件描述符。
因为文件描述符0,1,2对应的是系统调用的标准输入,标准输出,标准错误。所以如果我打开一个a文件,此时a文件描述符就是3,再打开一个b文件那么这个b文件的文件描述符就是4。以此类推。
inode
在Linux中,文件的内容和属性是分离的。保存属性的就用来保存属性,保存内容的就保存内容。但是不管是内容还是属性,都叫做数据。既然是数据,那么就要在硬盘里占用它自己的空间。所以在Linux中,用来保存文件属性的结构叫做inode,通常情况下,一个文件一个 inode 。
可以理解为在硬盘上有一块区域,这块区域叫做inode。那么既然一个文件就有一个inode,100个文件就有100个inode,那我怎么区分呢?我们知道一个进程有一个PCB ,用pid来标识。那么对于inode来说,也该有一个唯一的编号,就有inode号的概念。所以可以补充一下刚刚的概念。一个文件一个inode,一个inode号。虽然每个文件的inode不同,但是每个inode大小是一样的。打开一个文件时,操作系统就会把对应的文件的inode的部分属性摘录下来放在内存里。
Linux下,为了方便用户操作,所以给我们显示的都是一个一个的文件名,所以文件名必定和inode有一定的对应关系。
操作任何一个文件都是在特定目录下查找的,目录也是文件,所以目录里存放的是目录下所有文件的文件名和inode的映射关系。
查找文件的顺序: