在 Linux 系统中,一切都看成文件,当进程打开现有文件时,会返回一个文件描述符。
文件描述符是操作系统为了管理已经被进程打开的文件所创建的索引,用来指向被打开的文件。
当我们的进程启动之后,操作系统会给每一个进程分配一个 PCB 控制块,PCB 中会有一个文件描述符表,存放当前进程所有的文件描述符,即当前进程打开的所有文件。
进程中的文件描述符是如何和系统文件对应起来的?
在内核中,系统会维护另外两种表
文件描述符就是数组的下标,从0开始往上递增,0/1/2 默认是我们的输入/输出/错误流的文件描述符
在 PCB 中维护的文件描述表中,可以根据文件描述符找到对应了文件指针,找到对应的打开文件表
打开文件表中维护了:文件偏移量(读写文件的时候会更新);对于文件的状态标识;指向 i-node 表的指针
想要真正的操作文件,还得靠 i-node 表,能够获取到真实文件的相关信息
他们之间的关系
图解
总结
每次读写进程的时候,都是从文件描述符下手,找到对应的打开文件表项,再找到对应的 i-node 表
如何实现文件描述符重定向?
因为在文件描述符表中,能够找到对应的文件指针,如果我们改变了文件指针,是不是后续的两个表内容就发生了改变
例如:文件描述符1指向的显示器,那么将文件描述符1指向 log.txt 文件,那么文件描述符 1 也就和 log.txt 对应起来了
是输出重定向符号,< 是输入重定向符号,它们是文件描述符操作符
和 < 通过修改文件描述符改变了文件指针的指向,来能够实现重定向的功能
我们使用cat hello.txt
时,默认会将结果输出到显示器上,使用 > 来重定向。cat hello.txt 1 > log.txt
以输出的方式打开文件 log.txt,并绑定到文件描述符1上
dup 函数是用来打开一个新的文件描述符,指向和 oldfd 同一个文件,共享文件偏移量和文件状态,参考nodejs进阶视频讲解:进入学习
int main(int argc, char const *argv[])
{
int fd = open("log.txt");
int copyFd = dup(fd);
//将fd阅读文件置于文件末尾,计算偏移量。
cout << "fd = " << fd << " 偏移量: " << lseek(fd, 0, SEEK_END) << endl;
//现在我们计算copyFd的偏移量
cout << "copyFd = " << copyFd << "偏移量:" << lseek(copyFd, 0, SEEK_CUR) << endl;
return 0;
}
调用 dup(3) 的时候,会打开新的最小描述符,也就是4,这个4指向了3所指向的文件,操作任意一个 fd 都是修改的一个文件
dup2 函数,把指定的 newfd 也指向 oldfd 指向的文件。执行完dup2之后,newfd 和 oldfd 同时指向同一个文件,共享文件偏移量和文件状态
int main(int argc, char const *argv[])
{
int oldfd = open("log.txt");
int newfd = open("log1.txt");
dup2(oldfd, newfd);
//将fd阅读文件置于文件末尾,计算偏移量。
cout << "fd = " << fd << " 偏移量: " << lseek(fd, 0, SEEK_END) << endl;
//现在我们计算copyFd的偏移量
cout << "copyFd = " << c