文件描述符?文件流指针?
文件描述符、文件流指针及重定向
前言 一、文件描述符是什么? 二、文件描述符和文件流指针的关系 三、重定向 总结前言
在C标准库的I/O中我们提到文件流指针,在系统调用i/O接口中提到了文件描述符。这次来看看这两个东西有什么区别
一、文件描述符是什么?
由上图可知,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体,表示一个已经打开的文件对象,而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files(在pcb中),然后这个指针指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
我们尝试打印一下这个文件描述符的值;
然后我们再关闭1号描述符(stdout);
因为关闭了标准输出stdout,1号位置空出来,fd便会占据1号位置,数据并非写入到标准输出流,而是写入到当前“1”号描述符指向的my*file文件的缓冲区,由于“换行刷新缓冲“只能在stdout有效所以不打印;
然后我们再手动刷新缓冲区,1就会被打印出来。
然后我们再关闭“0”或者“2”号描述符;
此时我们便可以得出一个重要的结论暨文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。
二、文件描述符和文件流指针的关系
文件流指针:库函数IO接口的操作句柄FILE *fp;
文件描述符:系统调用IO接口的操作句柄 int fd。
库函数与系统调用接口的关系:库函数封装了系统调用接口。
文件流指针的标准输入输出和错误:stdin、stdout、stderr。
我们看一下源码:
stdin、stdout、stderr这三个都是struct _IO_FILE 类型的指针。
上图中将结构体重定义为FILE,就是文件流指针。
文件流指针归根究底就是个结构体,里面包含了一个成员变量,就是文件描述符,相当于文件流指针是对文件描述符的一层封装。
例如我们使用fopen时,实际上是把open返回的fd赋给了在文件流指针的结构体中封装的_fileno。
三、重定向
代码如下(示例):上面我们举的关闭1号描述符的例子中,本来应该输出到显示器上的内容,却输出到了我们指定的文件中,其中fd = 1,这种现象就叫做“输出重定向”,字面意思可以大概理解为把stdout用新的文件替代了。
常见的重定向有:> (清空重定向);>>(追加重定向)
举个栗子:
实质就是改变了数据流向。
重定向的原理:通过改变文件描述符对应位置的文件描述信息,进而改变所操作的文件,实现数据流向的改变。
dup2系统调用接口:
dup2(old fd, new fd);让new fd成为old fd的复制版。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
//close(1);
int fd = open("./_file_test.txt",O_CREAT|O_RDWR|O_TRUNC,0664);
if(fd<0)
{
perror("open error");
return -1;
}
dup2(fd,1);//
printf("fd = %d\n",fd);//打印文件描述符的值
fflush(stdout);
close(fd);
return 0;
}
1复制了fd的描述信息,所以1也指向fd指向的文件。也不会打印在显示屏上,而是将数据写入fd指的文件中。
总结
文件流指针是结构体,文件描述符是数组下标,重定向就是改变数据流向