文件描述符与文件流指针以及重定向

文件描述符?文件流指针?

文件描述符、文件流指针及重定向

  • 前言
  • 一、文件描述符是什么?
  • 二、文件描述符和文件流指针的关系
  • 三、重定向
  • 总结


前言

在C标准库的I/O中我们提到文件流指针,在系统调用i/O接口中提到了文件描述符。这次来看看这两个东西有什么区别


一、文件描述符是什么?

文件描述符与文件流指针以及重定向_第1张图片

文件描述符与文件流指针以及重定向_第2张图片

由上图可知,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体,表示一个已经打开的文件对象,而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files(在pcb中),然后这个指针指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
文件描述符与文件流指针以及重定向_第3张图片
我们尝试打印一下这个文件描述符的值;
在这里插入图片描述
然后我们再关闭1号描述符(stdout);
文件描述符与文件流指针以及重定向_第4张图片
因为关闭了标准输出stdout,1号位置空出来,fd便会占据1号位置,数据并非写入到标准输出流,而是写入到当前“1”号描述符指向的my*file文件的缓冲区,由于“换行刷新缓冲“只能在stdout有效所以不打印;
然后我们再手动刷新缓冲区,1就会被打印出来。文件描述符与文件流指针以及重定向_第5张图片

然后我们再关闭“0”或者“2”号描述符;
文件描述符与文件流指针以及重定向_第6张图片
此时我们便可以得出一个重要的结论暨文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

二、文件描述符和文件流指针的关系

文件流指针:库函数IO接口的操作句柄FILE *fp;
文件描述符:系统调用IO接口的操作句柄 int fd。
库函数与系统调用接口的关系:库函数封装了系统调用接口。
文件流指针的标准输入输出和错误:stdin、stdout、stderr。
我们看一下源码:
文件描述符与文件流指针以及重定向_第7张图片
stdin、stdout、stderr这三个都是struct _IO_FILE 类型的指针。
在这里插入图片描述
上图中将结构体重定义为FILE,就是文件流指针。
文件描述符与文件流指针以及重定向_第8张图片

文件流指针归根究底就是个结构体,里面包含了一个成员变量,就是文件描述符,相当于文件流指针是对文件描述符的一层封装。
例如我们使用fopen时,实际上是把open返回的fd赋给了在文件流指针的结构体中封装的_fileno。

三、重定向

代码如下(示例):上面我们举的关闭1号描述符的例子中,本来应该输出到显示器上的内容,却输出到了我们指定的文件中,其中fd = 1,这种现象就叫做“输出重定向”,字面意思可以大概理解为把stdout用新的文件替代了。
常见的重定向有:> (清空重定向);>>(追加重定向)
举个栗子:
文件描述符与文件流指针以及重定向_第9张图片
实质就是改变了数据流向。

重定向的原理:通过改变文件描述符对应位置的文件描述信息,进而改变所操作的文件,实现数据流向的改变。

文件描述符与文件流指针以及重定向_第10张图片
dup2系统调用接口:
文件描述符与文件流指针以及重定向_第11张图片
dup2(old fd, new fd);让new fd成为old fd的复制版。

#include 
#include 
#include 

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指的文件中。在这里插入图片描述


总结

文件流指针是结构体,文件描述符是数组下标,重定向就是改变数据流向

你可能感兴趣的:(linux,指针,文件流指针,文件描述符,重定向)