Linux——进程中被打开的文件

	C语言中有着许多对文件操作的函数,包括其他语言也有,但是从语言来了解文件有点浅显计算机的一切都离不开操作系统,那么文件跟操作系统也有着密切的关系,所以我们从系统层面来了解文件(在进程中打开的文件)

文章目录

  • 1.系统中被打开文件的认识
  • 2.C语言中的文件接口
    • a. fopen/fclose
    • b.fwrite/fread
    • c. 部分演示
  • 3. 系统调用接口open/close
    • a. open的参数和返回值
      • path和返回值
      • 标志位
      • mode
    • b. open的返回值fd再认识
    • c. 标准输入输出
    • d. 一切皆文件
  • 4.对文件结构体认识
  • 5. fd的再再认识
    • a. 追加重定向
    • b. 输入重定向
    • c. 问题的引入

1.系统中被打开文件的认识

  我们首先要知道文件 = 文件内容 + 文件属性
  其次为什么要从系统来了解文件?我们使用编程语言写好的程序也能打开文件对文件的数据进行修改。但是我们要知道,文件刚开始是在磁盘里的,语言写好的程序跑起来之后是一个进程,一个进程要打开文件,他能直接打开吗?很显然是不能的,因为文件没被打开前一般是在磁盘里的,而cpu只跟内存打交道,所以要打开一个文件必须要将它加载到内存中,那么谁来管理磁盘跟内存的交互呢?那肯定是操作系统。所以从语言来了解文件是不够本质的。并且从这里也就把文件分成两类:打开的文件和未打开的文件。而我们研究被打开的文件,也就是内存中的文件。
  再想一个问题,一个进程能带开多个文件吗?多个进程能打开多个文件吗?答案是可以的,Linux中万物皆文件,在一个进程跑起来的时候会默认打开三个流:标准输入、标准输出、标准错误。而这三个其中标准输入是键盘,标准输出和标准错误是显示器,而计算机中肯定会有着许多的进程。关于这些详细内容先不细谈,目前只要知道这三个流其实也是文件就ok了,所以一个进程可以打开多个文件,多个进程也可以打开多个文件。进程与打开的文件是1:n的关系
  这么说来,内存中会存在多个被打开的文件,而哪些文件被哪些进程打开了这些都需要被管理,所以文件需要被管理,操作系统管理的方法就是先描述,再组织,所以当一个文件要被打开时,除了要将文件加载到内存中,还要用文件结构体将文件描述好,这个结构体里面有着文件的信息可能有磁盘中的存储位置、文件名等等。然后再用数据结构比如链表将它们管理起来。也说明进程打开文件也是凭借操作系统来打开的,那么操作系统一定要封装系统调用才能让进程打开文件

2.C语言中的文件接口

  在这里我们只认识部分函数

a. fopen/fclose

  这两个是成对出现的,而fclose就是关闭一个文件,我们主要看fopen:
在这里插入图片描述
  它是一个库函数,它的参数第一个是文件的路径(这个路径可以是相对路径也可以是绝对路径),第二个是文件被打开的模式。它的返回值是一个库里封装的FILE的指针,这个指针会指向被打开的文件,如果打开失败会返回空值针。
  我们再看看文件可以有哪几种打开方式:

在这里插入图片描述

r模式:以只读方式打开文件,并且文件被指向的位置是文件内容的开头
r+模式:以读写方式打开问价,并且文件被指向的位置也是文件内容的开头
w模式:以读写的方式打开文件,在打开的时候会先将文件内容清空,然后指向文件内容的开始
w+模式:以读写的方式打开文件,在打开的时候会先将文件内容清空,然后指向文件内容的开始,当文件不存在的时候会创建文件
a模式:以追加(其实也是写)的方式打开文件,但是不会将文件内容清空,而且指向文件内容的末尾,当文件不存在时创建文件
a+模式:以读和追加的方式打开文件,不会清空文件内容,当读文件的时候从文件的开始读,写的时候从文件的末尾开始写。文件不存在时创建文件

b.fwrite/fread

  接下来我将演示打开文件,并对文件进行读写。在此之前我们还要认识一个函数:fread、fwrite
在这里插入图片描述
  这里它们的第一个参数是指向被写入/读的一段空间,第二个参数是每个元素字节大小,第三个是有多少个元素,第四个是要操作的文件。

c. 部分演示

部分演示:

在这里插入图片描述

在这里插入图片描述
  这里我们使用了fopen并且以w+的方式打开文件,刚开始我们这个目录底下是没有文件log.txt的所以要先创建好文件在向文件中写入上面代码中的要写入的内容。下面也是差不多,不过多解释
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
  我们发现我们上面的三个文件打开方式和之后的读写和Linux的重定向好像差不多。

3. 系统调用接口open/close

a. open的参数和返回值

我们上面知道,进程中打开文件,对文件的操作一定离不开操作系统,那么操作系统一定有着封装好的系统调用,来让进程能够对文件进行操作,而上面的进程是C语言编译好的程序,其中C语言中的文件打开对文件的读写肯定也是封装了系统调用。那么我们来认识两个系统调用open和close:

在这里插入图片描述
close不多介绍了就是关闭文件描述符所对应的文件。
在这里插入图片描述

首先是open,可以看到他有两个,这种好像是C++中的重载,怎么会在C语言中呢?其实这只是一种宏替换实现的并不是函数重载。
我们来介绍它的参数和返回值:

path和返回值

返回值:该函数打开文件成功后返回对应的文件描述符fd,失败返回-1
pathname:被打开文件的路径

标志位

后面两个参数我们要着重介绍一下,既然C语言中有着文件打开的方式,俺么系统调用里一定也有,这个就是文件打开的方式,但是它跟C语言中的传的方式不一样,这里使用了位操作的方式传,我们用代码来展示一下位操作传的标志问参数如何使用:
在这里插入图片描述

在这里插入图片描述
这就是标志位的使用,使用一个比特位就能描述一种状态。
这样我们就能介绍这个open中的flag参数怎么使用了,而手册里也告诉我们几种不同的打开方式,这里我们只介绍部分:

O_CREAT:文件不存在的话创建文件。
O_RDONLY:以读方式打开文件。
O_WRONLY:以写的方式打开文件。
O_TRUNC:打卡文件的时候会清空文件内容,并指向文件的开头。
O_APPEND:打开文件会指向文件的末尾。

我们看到这些参数也是全部以横杠+大写的方式命名,说明他们也只是一群宏常数罢了。

mode

接下来是第三个参数,mode:
我们打开一个文件log.txt。不在的时候创建它,在这里我们呢什么都没干,就把他打开后关闭了。
在这里插入图片描述

在这里插入图片描述
当我们看到如上结果的时候,发现文件的权限里怎么会出现S,并且文件是红的,这是因为文件的权限控制其实是乱码,而open中的mode就是控制这一权限的(被进程中创建的文件)。
在这里插入图片描述

在这里插入图片描述
这样就可以了,但是我们又发现,被进程创建好的文件设定的权限和实际的权限不一样,这是因为系统中有着掩码:
在这里插入图片描述
我们也可以在代码中设置进程中进程的掩码:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
但是不推荐这么做

b. open的返回值fd再认识

上面说到,open打开一个文件之后,会返回一个与之对应的文件标识符fd,文件标识符是什么?在C语言中使用fopen打开一个文件之后会返回一个指向被打开文件的FILE的一个指针,它与fd又有什么关系?接下来我们来一一解惑,既然涉及到了文件和进程那就又得从系统开始了解:
我们目前知道被打开的文件会被描述成文件结构体然后用数据结构组织起来(假设链表),那么在一个进程中,可能会需要打开多个文件,那进程和被打开文件又是如何联系起来的呢?其实它们是有着如下图的关系:
在这里插入图片描述
这其中文件如何加载到内存中先不说。
进程pcb中会有一个指针,这个指针指向一个指针数组,这个数组里面存储着被打开文件结构体的指针,这个数组也叫进程文件描述符表,那么这一张表让进程和文件而实现了解耦,就跟进程和内存的页表一样。我们现在来打开一下文件:
在这里插入图片描述
在这里插入图片描述
我们发现,文件标识符是一串连续的整数,这里直接提出结论:文件标识符就是进程文件标识符表的下标,操作系统访问文件就是根据文件标识符来访问
那么C语言中的FILE其实也肯定封装了fd,稍后我们可以进一步验证。
现在我们发现上面的数字只有3、4、5、6。0、1、2呢?我们知道进程在运行的时候会默认打开三个流:标准输入、标准输出、标准错误,那么结果显而易见,012就是这三个。代码说话:
在这里插入图片描述
在这里插入图片描述

那么这张图也说明了012对应的那三个标准输入输出流,FILE结构体里也封装了fd。
那么问题就来了:

为什么要默认打开这三个流?
文件描述符对应着着硬件,一切皆文件到底怎么理解?

c. 标准输入输出

首先来说明第一个问题:
默认打开这三个流,是为了让程序员能够默认进行输入输出的代码的编写(printf,scanf)。

d. 一切皆文件

第二个问题:
我们在使用open,fopen打开文件对文件进行各种操作,然后操作系统定时刷新文件缓存区,将操作得到的文件覆盖到磁盘中的文件中,说白了这些操作不还是和磁盘之间的交互吗?磁盘具有读写的功能,磁盘也是硬件,操作系统会和键盘交互,和网卡、麦克风、屏幕交互。那对于键盘来说该硬件只有读的功能,而屏幕只有写的功能。网卡可以读写,麦克风也只能读。这些功能肯定是在各自驱动中,有着对应的函数。而我们操作系统中的文件结构体中也肯定有着读写的函数指针,创建好一个文件对象的时候,我们让这个文件结构体的读写方法指向硬件的读写方法上:
在这里插入图片描述
每个硬件的读写的实现的方式肯定是不一样的,但是我们都是通过文件结构体对象来统一调用read和write方法来实现对硬件的读写,这种情况下我们把文件结构体看成父类,下面的键盘、屏幕等等看作子类,这不就是多态吗?而这一中调用的方式也叫做虚拟文件操作系统。所以对Linux来说一切皆文件。

4.对文件结构体认识

我们现在要知道当我们在进程中打开一个文件的时候,是怎么打开的:
我们打开一个文件,肯定是要对它进行各种操作,而文件无非就是文件内容+文件属性。所以文件结构体中应该会有文件的属性,以及对文件操作的各种方法集,操作文件不会在磁盘中操作,cpu不跟外设打交道,所以需要将文件加载到内存中,但是文件的加载又不是全部加载进来,而是,在创建好文件结构体的时候内存中还会构建一片文件缓冲区,文件的数据会加载到这里面。而这一系列操作都是由操作系统完成的。
那么我们使用系统调用打开文件后,返回系统标识符,用户根据这个文件标识符,对文件进行操作,而操作系统会到进程pcb中找到标识符指针数组的指针来找到那个数组,然后通过标识符下标来找到那个文件,再执行用户的操作。
在这里插入图片描述
那操作系统是如何对文件实现读写操作的呢?
首先是读:读肯定是读文件缓冲区的内容,当缓冲区中没有内容的的时候就会触发缺页中断,再让磁盘向缓冲区中加载(拷贝)。
写:我们在增加文件数据的时候,无非是开始增加,或者追加增加,这些都不需要加载文件到缓冲区,但是删除文件数据呢?这时候就需要将文件加载到缓冲区中了。而对文件内容的增加或删除在文件缓冲区中执行,然后由操作系统定时刷新文件缓冲区内容到磁盘中(也是一个拷贝的过程)。
那至此,我们得到,不论是文件的读还是写,都需要将文件加载到文件缓冲区中,并且用户对文件的读写对操作系统来说,也只是文件缓冲区的来回拷贝而已。

5. fd的再再认识

我们上面知道,进程创建好之后,会默认打开三个流,那假如我们关闭其中一个,再打开一个文件会怎么样呢?
在这里插入图片描述
在这里插入图片描述
关闭2呢?
在这里插入图片描述

在这里插入图片描述
不关闭
在这里插入图片描述
在这里插入图片描述
那我们就得出了fd的分配规则:寻找最小的,没有被使用的数据的位置,分配给指定的打开的文件
再认识两个个函数write/read:
在这里插入图片描述
在这里插入图片描述
返回值先不做介绍,使用起来很简单。
我们先对write和read和标准输入输出流进行简单的使用
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
需要注意的是这里我们没有将斜杠零算上去,那是因为“字符串结束的标志是斜杠零”这个是只在C语言中,对文件不适用。之后再验证。
在这里插入图片描述
我们再对上面进行一些小修改呢?

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
我们发现两个现象,一个是我们关闭1号文件描述之后对应的文件之后,再次打开一个文件,向1号文件写入时,写到了log.txt里。
第二个是当我们向1号文件里写入字符串时,字符串的斜杠零也被计算入内,但是log.txt中出现了乱码。
要是不计算呢?
在这里插入图片描述
在这里插入图片描述
就不会。
我们再看一个东西:
在这里插入图片描述
我们刚才的行为不就跟重定向一样吗?

a. 追加重定向

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

b. 输入重定向

在这里插入图片描述
在这里插入图片描述
重定向的本质其实就是修改文件描述符表的下标内容
我们上面是直接关闭了01两个流,有没有方法是不通过文件描述符分配规则关闭进行修改呢?
这里就有了dup2函数:
在这里插入图片描述
简而言之就是新的newfd就是最后保留下来的文件下标。
这个函数能实现文件描述符表级别的拷贝

c. 问题的引入

经过上面的了解我们再来一段这样的代码:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
关于这个问题,我们之后再说明,并且再次详细阐述重定向的问题以及文件机结构体部分具体成员的认识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/224001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之---- 排序算法

数据结构之---- 排序算法 什么是排序算法? 排序算法用于对一组数据按照特定顺序进行排列。 排序算法有着广泛的应用,因为有序数据通常能够被更有效地查找、分析和处理。 如图所示,排序算法中的数据类型可以是整数、浮点数、字符或字符串等…

NXP应用随记(四):eMios阅读随记-整体功能概述

目录 1、eMios IP介绍 2、时钟结构 3、通道类型 4、功能介绍 5、中断与DMA 6、EMIOS -通道分配建议(针对S32K312) 1、eMios IP介绍 Emios是什么?eMIOS提供了独立的通道(UCs),您可以配置这些通道来为不同的功能生成或测量时间事件。 每个eMIOS实例最…

本地项目添加到gitlab命令操作

gitlab上面创建一个跟项目名同名的文件夹 创建文件夹,填写信息 添加readme文档,先保存下创建的文件夹 回到项目,复制项目的git 地址 然后进入到本地项目的文件夹,如d:/workspace/spring-demo,右键打开git bash弹框 命令…

【C语言】二分查找(详解)

🎥 岁月失语唯石能言的个人主页 🔥个人栏专:秒懂C语言 ⭐若在许我少年时,一两黄金一两风 一、二分查找的思路 二分查找是一种高效的查找算法,尤其适用于有序数组。它的基本思想是通过将查找区间逐步缩小…

Amortized Bootstrapping of LWE:使用 BFV 打包处理

参考文献: [AP13] Alperin-Sheriff J, Peikert C. Practical bootstrapping in quasilinear time[C]//Annual Cryptology Conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 2013: 1-20.[MS18] Micciancio D, Sorrell J. Ring packing and amortized F…

基于CNN+数据增强+残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)+数据集+模型(四)

系列文章目录 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型(一) 基于CNN数据增强残差网络Resnet50的少样本高准确度猫咪种类识别—深度学习算法应用(含全部工程源码)数据集模型&#xf…

【动手学深度学习】(十四)数据增广+微调

文章目录 一、数据增强1.理论知识2.代码 二、微调1.理论知识 一、数据增强 1.理论知识 增加一个已有数据集,使得有更多的多样性 在语言里面加入各种不同的背景噪音改变图片的颜色和形状 使用增强数据训练 翻转 左右翻转上下翻转 不总是可行 切割 从图片中切…

【高效开发工具系列】DataGrip入门

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

文件操作2❤

一:文件的顺序读写 1:顺序读写函数 函数名 功能 适⽤于 fgetc 字符输⼊函数 所有输⼊流 fputc 字符输出函数 所有输出流 fgets ⽂本⾏输⼊函数 所有输⼊流 fputs ⽂本⾏输出函数 所有输出流 fscanf 格式化…

linux系统中出现大量不可中断进程和僵尸进程怎么办?

进程状态 当iowait升高时,进程很可能因为得不到硬件的响应,而长时间处于不可中断的状态,从ps或者top命令的输出中,可以发现它们都处于D状态,也就是不可中断状态。 通过top和ps可以查看进程的状态,S列表示…

Python学习开发mock接口

#1.测试为什么要开发接口? 1)在别的接口没有开发好的时候, mock接口(模拟接口) 2)查看数据, 避免直接操作数据库 #2.开发接口的顺序 1)安装flask flask是一个轻量级开发框架 pip install flask 2)开发一个接口 开发步骤: 1.实例化一个服务server:f…

普冉(PUYA)单片机开发笔记(9): FLASH 读写

概述 单片机的 ROM 容量虽然不大,PY32F003 有 64K 字节的 ROM,但实际应用中会在 MCU 中存储持久化的数据,例如:在物联网应用中,需要把物模型持久化,作为非易失性数据,掉电了也要保存。这就要用…

1845_emacs中一个中文乱码问题分析解决

Grey 全部学习内容汇总:GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1845_emacs中一个中文乱码问题分析解决 曾经有一次放弃过我自己的emacs配置,一个原因就是中文的支持。感觉我的配置跟其他人的配置显得有些…

深度学习(生成式模型)——ADM:Diffusion Models Beat GANs on Image Synthesis

文章目录 前言基础模型结构UNet结构Timestep Embedding关于为什么需要timestep embedding global attention layer 如何提升diffusion model生成图像的质量Classifier guidance实验结果 前言 在前几篇博文中,我们已经介绍了DDPM、DDIM、Classifier guidance等相关的…

leetcode做题笔记2415. 反转二叉树的奇数层

给你一棵 完美 二叉树的根节点 root ,请你反转这棵树中每个 奇数 层的节点值。 例如,假设第 3 层的节点值是 [2,1,3,4,7,11,29,18] ,那么反转后它应该变成 [18,29,11,7,4,3,1,2] 。 反转后,返回树的根节点。 完美 二叉树需满足…

【STM32单片机】旋转太空人设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器,使IIC OLED液晶等。 主要功能: 系统运行后,OLED显示动画界面。 二、软件设计 /* 作者:嗨小易(QQ&#x…

vue中实现PDF文件流预览

代码示例 <template><div class"print"><div v-if"!viewShow" class"opt-box"><div style"height: 700px; overflow: auto;"><el-table :data"tableData" border><el-table-column prop…

HTML基础标签

但实际上无论声明为中文还是英文都可以写&#xff0c;中文/英文 主要是浏览器在进行调用翻译功能的时候&#xff0c;会按照声明的语言来进行翻译。 标签语义&#xff1a; 标签的属性一般都是在第一个标签中定义该标签效果所拥有的属性。 即标签的作用是什么 <>标签功能…

CSS——标准流、浮动、Flex布局

1、标准流 标准流也叫文档流&#xff0c;指的是标签在页面中默认的排布规则&#xff0c;例如&#xff1a;块元素独占一行&#xff0c;行内元素可以一行显示多个。 2、浮动 作用&#xff1a;让块元素水平排列 属性名&#xff1a;float 属性值&#xff1a; left&#xff1a;…

做为一个产品经理带你详细了解--动态面板的使用

&#x1f4da;&#x1f4da; &#x1f3c5;我是bing人&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Axure》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一…