Linux——基础I/O2-操作系统如何访问文件|文件描述符的分配规则|重定向|如何理解一切皆文件

简介: 笔记

操作系统如何访问文件


文件可按照打开状态分为,被进程打开的文件(内存文件)和未打开文件


被进程打开的文件被加载到了内存,没打开的文件在磁盘上


操作系统要管理打开的文件,管理方式:先描述,再组织。操作系统用struct file进行管理文件,里面包含了文件的所有内容,包含属性,但文件的属性又来自哪?由于文件没有被打开时在磁盘上,文件=内容+属性,struct file里文件的属性就来源于磁盘。


进程和文件通过指针数组来进行维护,文件描述符的本质是数组下标

1.png2.png

task_struct中包含一个结构体指针,指针指向已打开的文件信息


2.pngfiles_struct结构体,该结构体有很多内容,其中有一个fd_array指针数组,数组默认大小为32或64


3.png


struct file里面有很多文件属性

4.png

操作系统是这样来访问文件的,fd_array也可以称为文件映射表/文件描述符表

5.png



文件描述符本质:数组下标


当用fopen打开文件时,底层调用open,open打开后会得到一个文件描述符,文件描述符被封装成FILE ,以FILE*的方式返回给fopen供用户去使用。


当用户开始fwrite的时候,传进来了一个FILE*(fopen的时候获得FILE*,fopen调用open获得fd,把fd放到FILE*里面),FILE*里面包含fd,并且FILE*里面封装了write,调用write之后就进入到了操作系统内部,然后自己执行了操作系统内部的write方法,执行write方法之后就找到了进程的task_struct,找到task_struct之后就找到了指针,然后找到files_struct,然后找到了fd_array[],这个数组再配合刚才传进来的fd,就找到了struct_file


文件描述符的分配规则


Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误。

0,1,2对应的物理设备一般是:键盘,显示器,显示器。


而现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。


于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。


每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数

组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的标。


所以,只要拿着文件描述符,就可以找到对应的文件



我们关掉0

6.png

此时fd是07.png




修改一下,close(0)改为close(2)


8.png


我们可以看到此时fd是2,这是因为fd的分配规则是:fd会找到最小的,没有被占用的文件描述符。


此时我们把1关掉

9.png



此时不打印,此时fd一定是1,没打印这是因为1是标准输出流。标准输出流是往显示器打印,我们此时关掉了1,所以不往显示器打印了

10.png

注释掉关闭文件

11.png



注释掉后,内容打印到了log.txt中,这是因为打印的时候printf默认往stdout打(因为1里被stdout占领),stdout是file结构体,这个结构体里fileno默认为1,我们关闭了1,fd便去占领了1,这个fd是打开了log.txt的返回值,也就是1此时对应的是log.txt,printf只认1,而1此时被log.txt占领,所以打印到了log.txt,这种现象叫做输出重定向。常见的重定向有:>, >>, <

12.png

printf和fprintf这些应该都往显示器打印(标准输出),关闭1之后,打印到了log.txt中,这是因为1此时被log.txt占领。

13.png

14.png15.png

当系统启动时,系统会默认打开三个文件,Linux一切皆文件键盘,显示器,显示器,系统会给这三个创建struct file对象,这三个文件分别是键盘,显示器,显示器。把这三个对象的地址填入0(标准输入流),1(标准输出流),2(标准错误流)所对应的指针数组中。在语言层面我们只在下标为1的地址里打印,如果1(默认为显示器)被改为了文件,我们则会把数据打印在文件中。0也是如此如果把0所在下标的内容改为其它文件地址,标准输入流此时就是这个文件,直接获取文件内容


重定向的本质其实是,在操作系统内,更改fd对应的内容指向

16.png

从指定的流 stream 读取一行,并把它存储在 buffer所指向的字符串内


此时我们输入什么,它打印什么

17.png



只读

18.png19.png

稍作修改 ,此时关闭了0,给log.txt分配了0,也就是说log.txt此时成了标准输入流

20.png

fgets从log.txt获取了字符串,这就叫输入重定向

21.png



重定向


man dup2,把oldfd拷贝给newfd,拷贝的不是fd这个数字,而是指针数组里面的内容

22.png23.png

此时如果要输出重定向,就是把myfile的地址放到下标为1的格子,此时应该


dup(3,1)

24.png

此时直接打印10086

25.png

.

26.png

输出重定向

27.png

把下标为fd的元素内容(log.txt的地址),拷贝给下标为1的元素

38.png

追加重定向,删掉O_TRUNC(清空)加上O_APPEND即可

29.png30.png


此时没有close(fd)

41.png42.png

添加close(fd),此时却什么都没打印,这是因为有缓冲区存在

43.png


44.png


dup2具有刷新缓冲区的操作

45.png


46.png



如何理解一切皆文件

Linux的设计哲学,体现在软件设计层上,Linux是用C语言写的。


用C语言实现面向对象,让结构体里面包含成员方法,使用函数指针,底层不同的文件,对应着不同的操作方法,下面这些设备都是外设,所以每一个设备的核心访问函数,都可以是read,write(这俩个代表I/O),所有的设备都可以有自己的read和write,但是,代码的实现,一定是不一样的,这种方式下硬件没有任何的差别,看待所有的文件的方式都统一成了struct file

47.png48.png

相关文章
|
3月前
|
Linux 网络安全
在Linux中,要想把iptable的规则保存到一个文件中如何做?如何恢复?
在Linux中,要想把iptable的规则保存到一个文件中如何做?如何恢复?
|
1月前
|
存储 Java iOS开发
MacOS环境-手写操作系统-43-dir命令的实现 和 文件写入
MacOS环境-手写操作系统-43-dir命令的实现 和 文件写入
30 0
|
2月前
|
Unix Linux API
Linux内核许可规则 【ChatGPT】
Linux内核许可规则 【ChatGPT】
|
3月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第17天】重定向在Linux中改变命令I/O流向,默认有&quot;&gt;&quot;覆盖输出至文件及&quot;&gt;&gt;&quot;追加输出至文件末尾,便于保存结果;使用&quot;&lt;&quot;从文件读取输入而非键盘,高效处理数据。文件描述符如0(stdin)、1(stdout)、2(stderr)标识I/O资源,支持读写操作。管道以&quot;|&quot;连接命令,使前一命令输出成为后一命令输入,如排序用户或找出CPU占用最高的进程,构建复杂数据处理流程。
49 9
|
3月前
|
Linux 网络安全
在Linux中,如何设置防火墙规则?
在Linux中,如何设置防火墙规则?
|
3月前
|
监控 Linux
在Linux中,如何监控磁盘I/O性能?
在Linux中,如何监控磁盘I/O性能?
|
3月前
|
Linux
Linux的I/O操作
Linux的I/O操作
|
3月前
|
存储 Unix Linux
Linux I/O 重定向与管道
【8月更文挑战第14天】输出重定向可将命令结果存入文件,如`&gt;`覆盖写入或`&gt;&gt;`追加写入。输入重定向从文件读取数据,如`&lt;`代替键盘输入。这些操作利用文件描述符(如0:stdin, 1:stdout, 2:stderr)管理I/O。管道`|`连接命令,使前一命令输出作为后一命令输入,便于数据处理,如排序用户`sort -t: -k3 -n /etc/passwd | head -3`或查找CPU占用高的进程`ps aux --sort=-%cpu | head -6`。
40 4
|
2月前
|
Linux API
Linux内核中的两种ID分配方式
Linux内核中的两种ID分配方式
|
3月前
|
网络协议 Linux
在Linux中,如何使用iptables 写⼀条规则?把来源IP为192.168.1.101访问本机80端口的包直接拒绝.
在Linux中,如何使用iptables 写⼀条规则?把来源IP为192.168.1.101访问本机80端口的包直接拒绝.
下一篇
无影云桌面