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

相关文章
|
6天前
|
Ubuntu Linux Go
golang编译成Linux可运行文件
本文介绍了如何在 Linux 上编译和运行 Golang 程序,涵盖了本地编译和交叉编译的步骤。通过这些步骤,您可以轻松地将 Golang 程序编译成适合 Linux 平台的可执行文件,并在目标服务器上运行。掌握这些技巧,可以提高开发和部署 Golang 应用的效率。
63 14
|
5天前
|
存储 NoSQL Linux
linux积累-core文件是干啥的
核心文件是Linux系统在程序崩溃时生成的重要调试文件,通过分析核心文件,开发者可以找到程序崩溃的原因并进行调试和修复。本文详细介绍了核心文件的生成、配置、查看和分析方法
32 6
|
7天前
|
存储 NoSQL Linux
linux之core文件如何查看和调试
通过设置和生成 core 文件,可以在程序崩溃时获取详细的调试信息。结合 GDB 等调试工具,可以深入分析 core 文件,找到程序崩溃的具体原因,并进行相应的修复。掌握这些调试技巧,对于提高程序的稳定性和可靠性具有重要意义。
45 6
|
8月前
|
缓存 Ubuntu 网络协议
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
127 1
|
6月前
|
小程序 Linux
【编程小实验】利用Linux fork()与文件I/O:父进程与子进程协同实现高效cp命令(前半文件与后半文件并行复制)
这个小程序是在文件IO的基础上去结合父子进程的一个使用,利用父子进程相互独立的特点实现对数据不同的操作
134 2
|
Linux
Linux系统应用编程 --- 文件I/O实现输出重定向
Linux系统应用编程 --- 文件I/O实现输出重定向
72 0
|
Linux API
Linux系统应用编程 --- 文件I/O
Linux系统应用编程 --- 文件I/O
95 0
|
缓存 Linux C语言
|
Java Linux Shell