基础IO(1)

目录

一 文件描述符(fd)

1 文件描述符是什么(文件描述符,文件指针,文件句柄。)

2 系统中文件的分类

3 系统中文件与进程的数量关系

4 如何实现进程和文件之间的管理

二 文件描述符分配规则

三 重定向

1 重定向原理

2 dup2

四 Linux一切皆文件的理解


一 文件描述符(fd)

1 文件描述符是什么(文件描述符,文件指针,文件句柄。)

我们在哪里知道有fd的存在的呢?刚开始的时候是调用文件操作的系统接口。比如:

我们调用open接口返回的fd就是文件描述符,他是012345……之类的数字。其中0,1,2,用来标识特定的文件,分别对应标准输入,标准输出,标准错误,012。

无论我们在语言层面上调用的是什么接口(fopen……),底层必定会封装open的系统调用接口,打开文件之后,必须直接或者间接地使用对应0,1,2的fd,才能向指定文件写入。

上述使我们产出的一个现象,先对fd有一个基本的认知——数字,后续我们其实就会知道,这些连续的数字就是数组下标,接下来会慢慢来解释的,包括为什么使用fd才能向指定文件写入,以及为什么要这么组织,这么组织的意义是什么。

2 系统中文件的分类


我们对文件进行一个分类:磁盘上的文件无外乎可以分成被打开的文件和没有被打开的文件。那么我们的系统中势必会存在很多很多的文件,假设Linux上有一百万个文件,包括:系统命令,配置文件,自己写的文件等等。虽然系统中有很多文件,但是被打开的文件只是其中的一部分。那些没有被打开的文件就被存储在磁盘上,等待你使用。毕竟我们不可能随时随地都用到所有的文件的。

并且磁盘上保存的文件就包含了对应的文件内容和文件属性。

这些没有被打开的文件叫做磁盘文件。

但是被进程打开的文件,这些文件叫做内存文件。打开文件是为了执行对应的代码,要执行对应的代码,要进行文件操作,要读写,根据冯诺依曼结构,必须加载到内存中才能被读写。

系统中的所有文件:内存文件和磁盘文件。都有文件内容和文件属性,一个被打开的文件加载到磁盘中,这些文件的内容和属性也有可能被加载进去。

3 系统中文件与进程的数量关系

当我们需要对应文件的时候,需要先找到再使用。如何找到?路径+文件名找到对应的文件,之后以特定的方式打开使用。并且访问文件是以进程的方式来访问的。只有这个程序被运行起来成为进程之后,进程内部才会执行对应的代码,帮我们访问并且操作对应的文件。

一个进程可以打开很多个文件,因此进程和文件对应的数量关系:1:n

如果每一个进程都打开文件,那么系统中就存在大量的文件。即使是目前没有打开那么多文件,但是由于未来可能会存在这种情况,那么OS也会设计有对应的方法来面对这种情况。

OS必须把大量的打开的文件管理起来,这些在内存中的文件需要先描述再组织地进行管理。OS管理文件:先描述再组织,每个文件包含struct FILE对象(描述),所有的文件用双链表连接起来(组织)。

因此内核中一定存在,为了管理对于的被打开的文件的struct FILE。它包含了文件的所有内容(内容和属性:常见的文件属性:文件大小,ACM时间,文件的拥有者所属组)。当我们打开文件的时候,这些文件的属性从哪里来呢?磁盘。文件天然在磁盘上,即使没有打开的时候,也在磁盘上。

4 如何实现进程和文件之间的管理

进程列表,文件列表在系统中存在着。如果想让进程能够很好地管理文件,那么他们存在对应关系,而这个关系是通过一个指针数组来维护的。如何维护呢?当我们打开一个文件的时候,会创建一个struct FILE对象。如果打开多个文件就会创建多个。每一个文件都会有自己对应的struct FILE对象。

OS会在数组(指针数组)fd_array中分配一个没有使用的空间,将对应的结构体以指针的方式填入到对应的位置,那么每一个数组的下标就会标定出对应的struct FILE。

最后我们通过返回数组的下标,并且把这个数组封装成一个结构体files_struct,以结构体指针的方式存储在task_struct的内部,从而实现进程对文件的管理。进程通过这个结构体指针,可以对应的管理一个个被打开的文件的files_struct,files_struct中的fd_array就可以找到存储了对应的一个个被打开的文件的指针,这些指针指向那些文件,实现进程对文件的管理。

OS中文件是如何被访问的也就是通过这样的逻辑链。

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

二 文件描述符分配规则

一般情况下,如果有需要被管理的文件,那么就要填入到对应的数组中,一般是去遍历这个数组,如果有空位,就往里面填写。并且0,1,2默认给了标准输入标准输出标准错误,因此一般是从3开始分配数组下标。但是如果把0,1,2关闭了,分配数组下标的时候也会分配到这里面去因此文件描述符的分配规则是:分配最小的未被占用的文件描述符给对应的文件。

一般情况下:

 

当我关闭0

 当我关闭1

发现这时候什么都不打印了

为什么会这样呢?

系统默认启动的时候,会打开三个文件:0,1,2-》标准输入标准输出标准错误,分别对应的硬件是键盘显示器显示器。

原本一般情况下是往显示器上打印的,但是close(1)之后,log.txt被填入了原先1下标所对应的位置,那么原先本来应该往显示器上打印就变成了往文件中进行打印了。所以显示器上看不到什么东西。

三 重定向

1 重定向原理

输入输出追加重定向的原理:Linux下一切皆文件,键盘显示器也是文件。默认一个进程会打开三个文件,标准输入标准输出标准错误,对应着键盘显示器显示器这些文件,fd_array中0,1,2的位置填入对应的文件指针。这就是系统给进程默认关联打开的三个文件。C语言上,使用fprintf这些接口,使用的fd是1,以fd为1的位置为准,但是里面的内容可能会发生变化。当我们关闭1号文件描述符的时候,相当于把进程和标准输出的关联关系给去掉了,在内核中,标准输出和1的关系就被解除了;之后我再次open一个文件,就会往1中填入对应的文件指针。这时候,fd==1的指向的文件对象变成了我打开的文件,那么后续我们打印的时候,就从标准输出变成了文件中。

2 dup2

操作系统提供了一个接口实现上述的重定向dup2接口

第一个参数是oldfd,第二个参数是newfd。oldfd-》newfd。并且必要的时候会把newfd给关掉,最终的内容和oldfd中的一样了。

演示使用:

 

 最终本应该打在显示器上的东西,被重定向到了文件中。

四 Linux一切皆文件的理解

Linux的设计哲学,体现在他的软件设计层面上。Linux是用C语言写的,如何用C语言实现面向对象,甚至是运行时多态呢?

c++中类是所有事务属性的集合,包含两个东西:成员方法和成员属性。

C语言struct和类类似,能够包含成员属性。但是在纯C语言中,struct中不能包含方法。因此在struct内部不存在成员方法。

但是如果我想实现struct内部包含成员方法呢?如何实现?

通过函数指针的方法来实现。

将来有了所谓的read和write方法,那么只要将struct中的函数指针指向对应的方法,让struct来调用方法,就实现了用C语言封装类。

重新理解文件:磁盘 显示器 磁盘 网卡 显卡这些是文件。底层不同的硬件,一定对应的是不同的操作方法。因此所有的外设都可以有自己的read和write,但是代码的实现一定是不一样的。但是上面的设备都是外设,所以每一个设备访问函数,都可以用read和write来进行封装。

操作系统要访问每一个硬件,所有的硬件要提供不同的方法。但是用户在使用的时候,为了统一,OS一切皆文件,设置了一个struc_file,打开一个对应的磁盘文件的时候,在内核中创建一个结构体,让函数指针指向对应的读写方法。

访问同一种类型的对象,却能访问不同的对象,多态的体现。语言就按照面向对象的来设计出来了。

VFS-》虚拟文件系统:就是对各种文件系统的一个抽象,它为各种文件系统提供了一个通用的接口,类似于c++中虚基类的作用,而每一种具体的文件系统则将其物理组织结构转换为虚拟文件系统的通用模型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值