C C++最新【Linux】基础IO,2024京东最新C C++面试真题解析

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

当我们要访问一个文件的时候,一般都是通过进程去访问,而文件是存在磁盘中的,所以肯定是进程通过操作次用来打开文件,那么操作系统一定要给进程提供调用文件的接口!

上图为操作系统提供的打开文件的接口,C中的 fopen函数,C++中的open函数,其实底层都封装了系统中的 open 接口。

调用 open 接口需要将文件路径和打开方式、文件权限作为参数传给 open,而 open 接口的返回值叫 **文件描述符 fd,**fd 是一个整数,它是进程访问文件的基本方式!在关闭某个文件的时候,只需要给 close 接口传这个文件的 fd 即可。

对于进程访问文件,用C程序来举例子:(下面先列举对应的C语言文件接口)

 

比如在C文件中调用 fopen 函数打开对文件做操作,当这个C文件被编译成一个可执行程序加载到并内存的时候,就会变成一个进程,当这个进程代码运行到 fopen 的时候,就会执行打开文件操作,文件就会被加载到内存中,一个C程序可以多次调用 fopen 函数,那么说明一个进程可以打开多个文件,那么多个进程在被轮转调度的时候,就可能会打开更多的文件!

所以 进程 :打开的文件  =  1:n

打开如此多的文件,那么在内核中必须形成对应的文件描述对象(里面存文件的属性等内容),通过某种数据结构将文件管理起来,来方便操作系统组织和访问。

文件打开的方式

第一个参数是要打开文件的路径,而第二个参数是打开的方式。

第二个参数,运行位图的方式,巧妙的传递了打开方式。

第一种传参方式类似于 fopen 函数中的以 “w” 方式打开(会清空文件重新写),而第二种传参方式类似于 fopen 中的以 “a” 方式打开(在已有文件后追加内容)

如果是创建文件的话,还可以将新文件的权限作为第三个参数传过去。

进程、系统、文件之间的关系

那么,在操作系统中,进程如何对打开的文件进行管理呢?

每一个被打开的文件,都会用一个 struct file 结构体来描述它,多个文件就用多个 struct file 结构体描述,并且将这些结构体用合适的数据结构管理起来。已知,在一个进程中,每一个被打开的文件都会用一个进程描述符 fd 来表示,这个 fd 就是进程访问文件的方式。

每个进程的 struct files_struct 中都有一个 struct files_struct* file 指针,指向同一个 struct files_struct ,而struct files_struct 中保存着一个数组 fd_array,这个数组中存储着当前进程打开的所有文件的地址,而这些文件的地址在这个数组中对应的下标就是 fd。也就是说,当一个文件打开被加载到内存的时候,它的地址就被存到了 struct files_struct 结构体对应的 fd_array 数组中,并且会返回它存储位置的数组下标 fd,以后就可以通过数组下标 fd 来得到文件地址,进而对文件进行访问!

操作系统访问文件,只认文件描述符!

但奇怪的是,当我们创建多个文件,并打印出文件描述符的时候,虽然 fd 是一个连续的小整数,很符合数组的连续存储,但却不是从零开始的,这是为什么呢?

Linux 中一切皆文件!!!

其实,一个进程在运行的时候,就默认打开了三个标准输入输出:

标准输入:键盘 stdin  ——> fd:0

标准输出:显示器 stdout——> fd:1

标准错误:显示器 stderror ——> fd:2

1 ——> 常规输出   2——> 错误输出(C语言中的 perror 就可以打印错误信息),也可以将正常输出信息和错误输出信息分别重定向到不同的文件中,方便管理和调试。

这三个硬件,在Linux 经过系统上层封装后,键盘、显示器等可以用统一的接口(read()、write())利用不同的变量来访问,其他的软硬件也都经过通过文件的访问方式封装,所以Linux 下一切皆文件!(VFS 虚拟文件系统)

这提前打开这三个文件是为了方便程序员写代码的。

std、stdout、stderr都返回一个 FILE* 指针(而FILE 其实是C语言提供的结构体类型),因为操作系统访问文件时只认文件描述符,所以由此推断:FILE 必定封装了文件描述符!

由此得出:每一种语言,在底层其实封装的是一种系统调用接口,这是由操作系统决定的,而且必须是一样的,不然在同一个操作系统中没法使用!

文件重定向

文件重定向的本质是:修改特定文件 fd 下标对应的文件地址

一般有三种重定向方式:

  • 输出重定向(先清空,再写入)
  • 追加重定向
  • 输入重定向
dup2(int oldfd, int newfd); // 系统调用接口

在文件被打开后调用,即可将 oldfd 对应的地址拷贝到 newfd 对应的地址处去,这样 oldfd 和 newfd 都指向同一个文件,在内核 struct file 中会有一个 f_count 的引用计数来控制,当要 close 文件的时候,f_count 先减1,只有当 f_count 减到 0 的时候,文件才会被关闭!

进程访问文件的步骤

总结:进程要访问,第一步,必须将文件数据先加载到文件缓冲区(内存中),然后通过进程中的struct files_struct* file指针,访问 struct files_struct,找到并遍历 fd_array 数组,找到最小的,未被使用的空间,将打开文件的地址存进去,然后就可以通过这个数组下标 fd 来访问文件了!

缓冲区

缓冲区分为:语言级缓冲区(用户级缓冲区)和内核缓冲区

缓冲区的主要作用是提高使用者的效率

缓冲区因为能暂存数据,必定有一定的刷新方式。

缓冲区刷新的一般策略有三种:无缓冲(立即刷新);行缓冲(行刷新,一般是显示器文件);全缓冲(缓冲区满了再刷新,一般是磁盘文件)

特殊情况:强制刷新;进程退出时,要刷新缓冲区。

我们平时使用的缓冲区,其实是语言级缓冲区(用户级缓冲区),从C语言缓冲区写入到OS/文件缓冲区中,这个工作叫做刷新。

以C语言为例:C语言给C库函数提供缓冲区,可以提高C库函数(IO类)的调用效率(都是在用户层),而IO的本质就是拷贝,先由用户级缓冲区拷贝至内核(文件缓冲区),再由文件缓冲区拷贝至文件(硬件)

正常情况下,在进行输入输出的时候,都有一个FILE,FILE是一个结构体,C语言中的缓冲区就在FILE中(FILE 中也包含了fd),FILE 可能会提供 buffer[]数组这种类型的东西作为缓冲区暂时储存数据。

int fsync(int fd);//将数据从文件缓冲区刷新到文件/磁盘中

文件系统

无论被打开的文件还是尚未被打开的文件,都要进行管理,路径的存在就是为了解决快速定位文件,因为无论什么对文件的操作,都得先找到!文件被管理起来,就是为了方便OS进行增删查改。

在磁盘中,通过 CHS 定位法(C、H、S)三个参数读取扇区位置,不同的扇区存不同的数据,这是用软件来控制的。

将磁盘高度抽象为以扇区大小为单位的数组,那么对磁盘的管理,就变成了对数组的管理,只要知道这个文件的起始扇区、大小,就可以通过索引来访问文件。

操作系统可以基于文件系统,按照文件块为单位进行数存取。

文件块都存储在磁盘中的 blocks[n] 数组中,对文件系统的管理,其实就是对 blocks 数组的管理;对存储设备的管理,在 OS 层面上,转换成了对数组的增删查改。

文件系统存储、寻址

我的文件信息分为内容和属性,内容和数据在原则上是分开存储的。很多管理文件的数据,得先让管理系统写入到块组中。

下图为文件系统图

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。政府管理各区的例子
  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了
  • GDT,Group Descriptor Table:块组描述符,描述块组属性信息,有兴趣的同学可以在了解一下
  • 块位图(Block Bitmap):Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用
  • inode位图(inode Bitmap):每个bit表示一个inode是否空闲可用。
  • i节点表:存放文件属性 如 文件大小,所有者,最近修改时间等
  • 数据区:存放文件内容

运行下面的指令

ls -li

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值