[Linux] 逐层深入理解文件系统 (1)—— 进程操作文件

server/2024/12/22 9:02:55/

标题:[Linux] 文件系统 (1)—— 进程操作文件

个人主页@水墨不写bug

        (图片来源于网络)

目录

 一、进程与打开的文件

 二、文件的系统调用与库函数的关系

1.系统调用open()        

三、内存中的文件描述符表

四、缓冲区的理解 

五、俯瞰IO 


正文开始:

 一、进程与打开的文件

        C/C++都提供了对文件进行操作的函数接口,想要对文件操作:无论是往文件中写入,还是从文件中读出,都需要满足一个前提条件:文件被打开。

        文件被打开,意味着文件被从磁盘中加载到内存中。进程是我们写的C/C++指令编译行成的运行起来的程序,本质是我们想要完成想要某一个任务。于是,我们不得不考虑加载到内存中的文件与进程之间的关系。

        文件是在磁盘中存储的,磁盘是一个硬件外设,对文件操作本质就是对磁盘这个硬件操作。但是用户没有权利直接向硬件写入。想要完成对硬件操作,需要 软硬件资源的管理者——操作系统的帮助。但是操作系统不相信如何用户,于是需要用操作系统提供的安全的访问操作系统数据的方式——系统调用。

        于是,我们通过分析可以推测——我们使用的

        fopen/fwrite/fread/fprintf/scanf/printf/cin/cout

等一系列的C/C++的文件操作的库函数,本质都是对系统调用的封装!

        这样一来,为了搞清楚封装的细节,我们需要先知道如何使用系统调用。

 二、文件的系统调用与库函数的关系

1.系统调用open()        

open()函数原型:

 

参数:

        pathname:想要打开的文件的名称;

        flags:打开的文件的方式选项,常见的选项有:

O_WRONLY: 以写的方式打开文件。

O_CREAT:     如果不存在就创建文件。

O_TRUNC:    每一次打开清空文件内容。

O_APPEND:打开文件之后不清空文件内容,而在后面追加。

        mode:如果成功创建了文件,文件被创建出来的默认权限设置。

返回值:

        一个整数int,被称为文件描述符(file descriptor)。

         其实,C语言的fopen函数在的不同打开方式,都对应一种flags的组合。C语言对文件打开方式有"w" "r"等等的区分,由于C语言fopen函数底层调用的还是open系统调用,所以自然会发现这样的对应关系:

         这两个调用本质都是对第一个系统调用函数open的调用,只不过第二种C语言式的函数调用对第一种系统调用进行了封装,在函数内部增加了语言级别的缓冲区等的操作,并且对返回值也进行了封装,把int类型的返回值封装成了FILE结构体指针类型的返回值。

        为什么C语言要这样做呢?别急,接下来我们对文件有了深入的理解认识之后,你就会体会到C语言的良苦用心了。


三、内存中的文件描述符表

        在上面的理解中,我们发现  系统调用open()函数  的返回值是一个整形int,对应的,我们发现  系统调用close()  函数也是通过一个int整数来关闭文件的,这非常令人费解,为什么仅仅凭借一个整数就可以操作整个文件的开关?

        在操作系统中,运行有成百上千的进程,每时每刻都有进程的创建,消亡。每一个进程都可以打开文件,并且一个进程可以打开不止一个文件!这就意味着操作系统必须要有一个高效的管理打卡的文件的方式,这个方式就是:

先描述,再组织!

         在内存中,不止有进程的PCB(task_struct),还有描述文件的数据结构:文件描述符表

        我们可以暂时把文件描述符表抽象理解成一个数组,这个数组存储文件的数据。磁盘中的文件被加载到内存中,就是通过这个数组来维护的。

        而open的返回值,就是打开的文件在这个数组中对应的下标!!

 

        如上图,一个个的文件被加载到内存中后,会被存储在files_struct这个结构体数组中,这个数组就是文件描述符表!

        不同的文件存储在不同下标位置:

 

         于是每一个文件就有了一个对应的下标:fd;这也就解释了为什么操作系统为什么可以拿着一个整数来对文件进行操作:因为操作系统可以通过一个整数下标来标识一个文件。

 


         当我们一次性打开并关闭多个文件,重复几次,会发现fd的分配规则:

                1)fd的0,1,2被默认提前分配为标准输入(键盘),标准输出(显示器),标准错误(显示器)。(C语言的stdin,stdout,stderr本质也是对这三个文件的封装)

               2)fd的分配机制是按照从小到大的顺序分配fd下标。

 


四、缓冲区的理解 

        语言有语言的缓冲区,系统有系统的缓冲区,这两个缓冲区存在的目的都是为了提高IO效率:

        1)因为访问外设与CPU的速度相比非常慢,所以系统缓冲区存在的意义就是尽量减少对外设的访问,当向缓冲区写入一定量的数据之后,操作系统会一次性把数据刷新到磁盘中。 

                

         2)系统调用的使用成本比库函数要高的多,因为操作系统太忙了,每一次调用系统调用都是请求操作系统配合用户一次,频繁调用会导致效率损失。所以语言缓从区存在的意义就是尽量少调用系统调用,当我们向语言级缓冲区写入一定的数据之后,C语言函数会一次性把数据刷新到系统级缓冲区。

        


五、俯瞰IO 

        这时,我们整体俯瞰io的过程:

        当我们打开一个文件,操作系统会调用open:

        1)创建file结构体;

        2)开辟文件缓冲区内容,加载问价数据(延后)

        3)查进程的文件描述符表

        4)file地址,填入对应的表的下标中

        5)返回下标

        当我们调用fopen库函数,会在上面操作的基础上创建语言级缓冲区等操作,本质是为了改善用户体验,提高效率。

         为什么C语言要封装系统调用?

        1)提高效率,改善用户体验

        2)C语言有多个不同的在不同的平台上实现的版本,具有跨平台性。但是我们所讲的系统调用,仅仅是Linux的,对于其他操作系统就不适用了。


完·~

未经作者同意禁止转载 


http://www.ppmy.cn/server/131668.html

相关文章

Android 10.0 滑动解锁流程

前言 滑动解锁相对于来说逻辑还是简单的,说白了就是对事件的处理,然后做一些事。 这里主要从锁屏的界面Layout结构、touchEvent事件分发、解锁动作逻辑几个方面进行源码的分析。 锁屏的界面Layout结构分析 StatusbarWindowView 整个锁屏界面的顶级 Vi…

【spring ai】java 实现RAG检索增强,超快速入门

rag 需求产生的背景介绍: 在使用大模型时,一个常见的问题是模型会产生幻觉(即生成的内容与事实不符),同时由于缺乏企业内部数据的支持,导致其回答往往不够精准和具体,偏向于泛泛而谈。这些问题…

单体到微服务架构服务演化过程

单体到微服务架构服务演化过程 架构服务化 聊聊从单体到微服务架构服务演化过程 单体分层架构 在 Web 应用程序发展的早期,大部分工程是将所有的服务端功能模块打包到单个巨石型(Monolith)应用中,譬如很多企业的 Java 应用程序…

现代数字信号处理I-P3 MVUE学习笔记

目录 1. 参数估计问题的提出与本质 2. 估计的性质 2.1 Ancillary(多余估计) 例1,Ancillary估计量 2. Uniformly Optimal 3. Sufficiency充分性 3.1 统计量充分性定义 例2:利用充分统计量定义获取伯努利分布的充分统计量 …

File IO

Unix标准为程序员提供了一系列的通用IO(无缓冲IO)接口以实现文件读写操作,原书第三章主要所涉及到的系统接口主要针对普通文件为操作目标。通用IO相比于标准IO的最大的区别在于没有缓冲机制,只要调用一次标准IO,就进行IO,而不是像…

finebi面试题精选

‌‌FineBI‌是由‌帆软软件有限公司开发的一款商业智能(Business Intelligence)产品,旨在通过最终业务用户自主分析企业已有的信息化数据,帮助企业发现并解决存在的问题,及时调整策略以做出更好的决策,从而…

Adobe Photoshop Lightroom(图像处理软件) v8.0 中文版

Adobe Photoshop Lightroom 是由 Adobe 公司推出的一个专业的图像处理软件,主要用于数字摄影后期处理。Lightroom 与 Adobe Photoshop 不同,它是专门为数字摄影而设计的软件,注重于整个摄影工作流程的管理和处理,能够帮助摄影师更…

Go语言学习第一章

1、搭建Go开发环境-安装和配置SDK 基本介绍: SDK的全称(Software Development Kit软件开发工具包) SDK是提供给开发人员使用的,其中包含了对应开发语言的工具包 2、SDK下载 Go语言的官网为:golang.org,无法…