• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

Linux——基础IO(二):文件描述符,文件流指针,重定向

互联网 diligentman 2周前 (04-09) 11次浏览


文章目录:

  • 1. 文件描述符
    • 1.1 文件描述符的实质:
    • 1.2 文件描述符的分配规则:
    • 1.3 一个进程最大可以开多少个文件描述符?
  • 2. 文件流指针(FILE)
    • 2.1 前言
    • 2.2 文件流指针的本质
    • 2.3 深究FILE
  • 3. 文件流指针和文件描述符的区别
  • 4. 重定向
    • 4.1 重定向的命令符号
    • 4.2 重定向的原理
    • 4.3 使用dup2系统调用

1. 文件描述符

文件描述符就是内核当中 fd_array 数组的下标,是一个正整数

我们写出如下代码,并在代码最后加上一个循环,让代码不要退出
Linux——基础IO(二):文件描述符,文件流指针,重定向
运行程序,后查看当前进程
Linux——基础IO(二):文件描述符,文件流指针,重定向
如下图所示:

文件描述符:

  • 0–>标准输入
  • 1–>标准输出
  • 2–>标准错误
    Linux——基础IO(二):文件描述符,文件流指针,重定向

1.1 文件描述符的实质:

在进程中有一个结构体指针(struct file_struct* files),指向了一个结构体(struct files_struct),而在这个结构体(struct files_struct)中有一个数组,这个数组的下标就是文件描述符,数组的每个元素的类型是struct file*,struct file* 这个结构体指针指向 struct file这个结构体(保存了文件的元信息),而最终和磁盘打交道的就是struct file这个结构体
Linux——基础IO(二):文件描述符,文件流指针,重定向

1.2 文件描述符的分配规则:

最小占用原则:在数组中找到当前没有被使用的最小的一个下标,作为新的文件描述符

如下代码所示,我们关闭了2,会发现fd不是3而是2
Linux——基础IO(二):文件描述符,文件流指针,重定向
Linux——基础IO(二):文件描述符,文件流指针,重定向

1.3 一个进程最大可以开多少个文件描述符?

进程最大打开文件描述符个数是由操作系统中一个参数限制的,可以通过命令:ulimit -a查看到一个open files,open files后面的值就是进程可以打开的最大文件描述符个数

Linux——基础IO(二):文件描述符,文件流指针,重定向

最大文件描述符个数更改:ulimit -n

2. 文件流指针(FILE)

2.1 前言

我们可以先cd到 /usr/include目录下,在此目录下我们可以看到所有的头文件
Linux——基础IO(二):文件描述符,文件流指针,重定向
我们在用vim打开stdio.h
Linux——基础IO(二):文件描述符,文件流指针,重定向
此时我们就可以找到FILE
Linux——基础IO(二):文件描述符,文件流指针,重定向

2.2 文件流指针的本质

  • FILE文件流指针是一个typedef之后的值,本质是一个结构体
  • 在“/usr/include/stdio.h”目录下可以看到

2.3 深究FILE

而我们怎么才能查看FILE这个结构体中的内容呢?

我们可以通过grep "struct _IO_FILE {" . -R命令进行搜索,此时我们会看到,这个结构体的位置在 ./libio.h
Linux——基础IO(二):文件描述符,文件流指针,重定向
此时我们只需vim进入libio.h,在进行搜索即可找到
Linux——基础IO(二):文件描述符,文件流指针,重定向
在struct _IO_FILE这个结构体中,我们可以看到读缓冲区写缓冲区
Linux——基础IO(二):文件描述符,文件流指针,重定向
int _fileno;当中保存的内容就是文件描述符
Linux——基础IO(二):文件描述符,文件流指针,重定向
在此我们可以更清楚的了解文件流指针的工作原理,如下图所示:
Linux——基础IO(二):文件描述符,文件流指针,重定向

     之前在进程终止的时候说的刷新缓冲区:指的是C库当中维护的读写缓冲区
     借助上图我们可以理解:_exit()函数之所以不会刷新缓冲区,是因为_exit()函数是内核代码,直接操作内核结束结束了进程,而此时并不会通知上层的C库,所以,C库维护的缓冲区完全在无感知的情况下进程就终结了

3. 文件流指针和文件描述符的区别

  • 文件流指针是一个结构体,在结构体内部保存了文件描述符
     
  • 文件描述符是一个正整数,其含义为fd_array数组的下标
     
  • 文件流指针维护了读写缓冲区

4. 重定向

4.1 重定向的命令符号

 > :清空重定向,将文件内容清空之后在重定向

测试如下:

我们vim一个abc文件,可以看到abc文件中的内容如下图所示:
Linux——基础IO(二):文件描述符,文件流指针,重定向
然后我们使用 ls > abc 命令之后可以看到abc中的内容已经被清空重定向了
Linux——基础IO(二):文件描述符,文件流指针,重定向

 >> :追加重定向,直接在文件的尾部进行重定向

测试如下:
我们对abc文件进行追加重定向,可以看到,直接在文件的尾巴进行了重定向
Linux——基础IO(二):文件描述符,文件流指针,重定向

4.2 重定向的原理

将 fd_array 数组当中的元素struct file* 指针的指向关系进行修改,改变成为其它的struct file结构体的地址

Linux——基础IO(二):文件描述符,文件流指针,重定向

4.3 使用dup2系统调用

int dup2(int oldfd, int newfd);

通过man手册我们可以对dup2函数进行一些了解,我们会看到这样一段话
Linux——基础IO(二):文件描述符,文件流指针,重定向

  • newfd的值是拷贝于oldfd的值,及newfd的值来源于oldfd
     
    eg:上文重定向原理图解中的过程可以写为:dup2(3,0);

Linux——基础IO(二):文件描述符,文件流指针,重定向

(1) 如果必要,使用dup2进行重定向的时候,会先关闭newfd
 

  • 必要:oldfd是正常的文件描述符
     
  • 如果oldfd不是一个有效的文件描述符,则不关闭newfd,重定向失败 eg:dup2(10,0) 没有文件描述符10
     
  • 如果oldfd是一个有效的文件描述符并且和newfd是相同的文件描述符数值,则dup2什么事情都不有干 eg:dup2(0,0);

(2) 将oldfd的值拷贝给newfd

注意:
      一般C库函数写入文件时是全缓冲,而写入显示器是行缓存

      eg:“n”==》行缓冲


喜欢 (0)