说明,上图展示了linux系统中,用C语言打开文件后,内核所维护的几个结构。
最左边那个图是以process为范围的,每个process中不同的文件描述符对应不同的左边结构中的一个entry。
中间那个结构是系统范围内的一个结构,是跨进程的。
最后边那个结构式对应文件的,即每个文件对应一个v-node结构。
有以下几点需要注意:
1、不同进程打开的同一个文件同一个文件是拥有不同的file table entry(中间那个结构)。因为是对一个文件所以会拥有相同的v-node(最右边那个结构)。
2、同一个进程可以连续打开同一个文件两次(第二个打开可以在第一个打开没有关闭的情况下进行),不会出错。这两次打开会对应不同的文件描述符(最左边那个结构),并且会拥有不同的file table entry。但会拥有相同的v-node。
可以使用下面测试代码验证:
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include <stdio.h>
#include<errno.h>
int
main(int argc, char *argv[])
{
int fd,fd1;
struct stat buf;
off_t offset;
fd=open("testtestt.c",O_RDWR|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
if(fd==-1)
{
perror("open fd error:");
printf("\n");
}
else
printf("fd=%d\n",fd);
fd1=open("testtestt.c",O_RDWR|O_CREAT,S_IRWXU|S_IRWXG|S_IRWXO);
if(fd1==-1)
{
perror("open fd1 error:");
printf("\n");
}
else
printf("fd1=%d\n",fd1);
lseek(fd,100,SEEK_SET);
offset=lseek(fd,0,SEEK_CUR);
printf("offset fd=%ld\n",offset);
offset=lseek(fd1,0,SEEK_CUR);
printf("offset fd1=%ld\n",offset);
close(fd);
close(fd1);
return 0;
}
说明:以上代码连续两次打开同一个文件(第一个打开没有关闭时打开调用第二个打开),然后对第一个打开的描述符调用lseek()改变其offset(file table entry中的一项),然后输出两个文件的当前offset,查看其是否相同。
3、用dup()、dup2()函数复制的文件描述符会拥有不同的描述符(最左边那个结构),但会拥有相同的file table entry。
4、使用fork()函数唤醒子进程时,在父进程打开着的描述符,在子进程中仍然打开着。并且他们拥有相同的file table entry。
5、使用exec()函数唤醒其他进程时,被唤醒进程会拥有唤醒进程的CLOS_ON_EXEC没有打开的文件描述符,并且与以前的进程使用的是相同的file table entry。