Linux---文件(2)---文件描述符缓冲区(语言级)

目录

文件描述符

基础知识

文件描述符

对“Linux一切皆文件”的理解

文件描述符分配规则

缓冲区

刷新策略

存放位置

解释一个"奇怪的现象"

格式化输入输出


文件描述符

基础知识

在系统层面上,文件操作都是通过文件描述符来操作的。

程序在启动的时候,会默认打开三个文件流stdin(标准输入流)、stdout(标准输出流)、stderr(标准错误流)。这三个也是文件,在程序启动时由操作系统默认打开,程序退出时由操作系统默认关闭。这三个文件也有其对应的文件描述符,分别为0、1、2。所以,我们在程序中打开的文件的文件描述符是从3开始的。

C语言的文件接口,本质就是封装了系统调用。

C语言封装系统调用本质上是为了解决跨平台性、可移植性。在任何平台都使用的同一套C语言对文件的接口,底层会去调用不同平台的系统调用接口。在语言上访问文件的接口是不一样的,但只要是在一个系统中,底层调用的系统调用接口都是相同的。

在系统的角度来看,操作文件依赖的是文件描述符。

而在C语言中,操作文件却用的是文件指针。

这是因为C语言中的FILE是C语言标准库自己封装的一个结构体,在FILE结构体中,必定封装了文件描述符、文件属性、文件内容指向等字段。

进程创建出来后,操作系统将stdin、stdout、stderr文件加载到内存,由FILE结构体对象将其文件的信息记录下来,并将对象节点以某种数据结构进行连接管理。由于这三个文件已经占用了0、1、2,所以我们在进程中打开的文件的文件描述符就从3开始。

文件描述符

文件描述符本质是数组下标。

操作系统要管理被进程打开的文件,就要"先描述,再组织",利用特定的数据结构节点来管理被打开的文件,此后,对被打开的文件做管理就变成了对特定的数据结构进行管理了。

CPU执行到处理文件时,内部通过文件描述符调用相关的系统调用接口,操作系统通过访问进程PCB中的struct files_struct结构体指针,通过这个指针找到文件描述符表,再以文件描述符作为下标索引对应管理文件的struct file结构体的指针,通过对这个结构体进行处理,等到文件退出时再将修改的信息对磁盘文件中做更新。

在缓冲区上访问文件内容,缓冲区通过与磁盘的刷新来对文件做修改操作。

文件描述符本质上就是数组下标。

对“Linux一切皆文件”的理解

1、每个硬件都有与之匹配的特有的读写方法。

2、操作系统要管理每个硬件("先描述,再组织")

3、利用类似多态调用的思想,实现调用时调用指针所指向的对象的方法。

操作系统用上层统一的接口来屏蔽硬件读写差异。

文件描述符分配规则

文件描述符分配规则:最小的没有被使用的文件描述符会优先分配给最新打开的文件

系统打印时如果没有特殊要求,系统只在stdout文件中去打印,本质上是系统只在文件描述符为1的文件中去打印。

当文件描述符为1的文件是stdout时,则输出到显示器文件上。

当文件描述符为1的文件是其他文件时,则输出到其他文件上去。

所以,修改1号文件描述符的文件,即可发生类似于重定向的操作。

重定向的本质就是修改文件描述符表中指针指向的内容,将这个内容修改为其他文件的地址(覆盖掉原来的地址即可),写入操作就会写入到其他文件中去。

直接覆盖文件描述符表对应下标的内容接口

这种处理会导致一个文件被多个指针指向,操作系统会对此情况进行处理。

printf/fprintf/sprintf函数在输出的时候都去stdout文件中输出,

本质是都输出到文件描述符为1的文件中去。

scanf/fscanf/sscanf函数在输入的时候都去stdin文件中去读取,

本质是都从文件描述符为0的文件中去读取。

重定向操作也是通过dup2系统调用接口,将对应的文件描述符表的内容做修改,从而实现的。

缓冲区

缓冲区本质是一块内存区域。

缓冲区的设计是用空间换时间,存在本质是为了提高用户的操作效率。

此缓冲区为语言层面的缓冲区,与操作系统内核中的缓冲区无关。

C语言本身自带缓冲区。

缓冲区是将数据聚集起来,做少次数的数据传输,来提高效率。

以用户写入操作举例,用户通过调用用户级接口向指定文件写入数据,C语言会将用户传的数据写入到自己的缓冲区中,等到缓冲区达到某种规则时,C语言会将自己缓冲区内的内容通过系统调用接口写入到操作系统内核中该进程对应的缓冲区中(C语言会通过进程PCB中的文件描述符表,以文件描述符为下标索引到管理文件的节点,通过节点的字段找到该进程对应的内核缓冲区)。由操作系统决定何时将缓冲区中的内容写入刷新到磁盘文件中。

每个进程都有自己的内核缓冲区。

系统调用本身是有成本的。

单次调用一次系统调用的效率高。比如:申请相同大小的空间,第一种方法:多次调用系统调用且每次申请较小的空间资源。第二种方法:少次调用系统调用接口且每次申请较多的空间资源。这两种方法,第二种是比第一种的效率高的,所以我们应该尽可能的减少调用系统调用接口的次数。

操作系统深知应尽可能少调用系统调用,所以在内存空间足够的情况下,对于系统调用接口,会在内存中预先申请大量的空间资源来提供使用。比如:我们调用fork系统调用的时候,看似我们调用了系统调用,其实是操作系统提前在内存中申请的空间资源,提前创建空壳进程PCB、页表、mm_struct等,等到我们调用该系统调用时,操作系统就不用给我们重新申请资源、创建PCB等操作了,就直接使用内存中提前准备好的空壳进程的一套资源,只需要写入对应的字段即可,这种做法提高了操作系统的效率。当然,当内存中资源不足的时候,操作系统会做各种挂起、终止不必要进程等操作,来保证操作系统的正常运行。

缓冲区就是提前申请好的内存空间。比如:我们在使用数据结构插入接口时,会直接插入到提前申请好的内存空间上去,不用再调用扩容机制接口,来提高效率。

执行多次写入操作都是将数据写入到语言级缓冲区中,此缓冲区按照自己的机制/策略,在合适的时机调用系统调用接口,将数据一次性全部写入到内核缓冲区中,再由操作系统决定,将内核缓冲区中的数据刷新到磁盘上,此操作有效减少了调用系统调用接口的次数,提高效率。

用户级别接口只需要将数据写入到语言级的缓冲区中,语言层就会给用户返回调用结果。从语言级缓冲区到内核缓冲区再到刷新到磁盘文件中这个过程,不用用户关心处理,这操作由操作系统整体把控,此操作还有效提高了语言级接口的使用效率。

刷新策略

语言级缓冲区通过系统调用接口将数据刷新(拷贝)到内核缓冲区的策略为:

1、无刷新---无缓冲:没有设计缓冲区,每次调用语言级接口都会调用系统调用。

2、行刷新:以'\n'字符为标志,每次刷新'\n'字符之前的数据,显示器文件就是行刷新。

3、全缓冲:缓冲区被写满后,才会被刷新。普通文件就是全缓冲。

如果上述情况都没有满足时,比如:行刷新但没有检测到'\n'、全刷新但缓冲区没有被写满

1、强制刷新接口

2、进程退出时,会自动刷新

存放位置

语言级缓冲区本质是在管理文件的FILE结构体中,由该FILE结构体维护。

每一个文件都有对应的FILE结构体,都有对应的语言级缓冲区。

语言级缓冲区被管理该文件的FILE结构体维护,内存缓冲区被进程PCB维护。

C语言封装的意义:

1、将数据写入到语言级缓冲区中

2、调用系统调用

解释一个"奇怪的现象"

C语言的缓冲区,如果是向显示器文件中输出,刷新方案就是行刷新,如果是向普通文件中输出,刷新方案就是全刷新。

系统调用接口会直接将用户输入的数据写入到内核级缓冲区中,C语言级接口会先写到语言级缓冲区中再写到内核缓冲区中。

格式化输入输出

FILE类型是C语言提供的,就存在C语言级缓冲区。

stdin一般都有输入缓冲区,stdout一般都有输出缓冲区。

我们在使用printf函数时,是向显示器文件中做输出,但显示器文件属于字符设备文件,只认识字符,不能识别我们输入的非字符数据类型,此种情况,就是格式化输出的工作了。

格式化输出本质是将非字符类型转化为一个个的字符,然后拷贝至发送缓冲区中,然后由printf函数获取输出。

printf函数输出,实际上输出的都是字符。在printf函数内部,都是以字符来对待数据的,格式化输出会将全部的非字符类型转化为字符类型,拷贝到发送缓冲区中,格式化输出时,再将其拷贝至语言级缓冲区中即可。

格式化输入,实际上将用户输入的数据视作字符,保存在stdin输入缓冲区中,由格式化输入将一个个的字符转化为各种数据类型,再通过变量地址写入到变量中。

数据流动本质上就是拷贝数据,所有的文件接口本质上也是拷贝接口。

我们所学的C++中的cin、cout本质都是类,都存在缓冲区,我们将这种语言级别的缓冲区称作字节流,读写都是从字节流中获取。

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

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

相关文章

leetcode回文链表

leetcode 回文链表 题目 题解 两种方式进行题解 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, Li…

JavaWeb JavaScript 9.正则表达式

生命的价值在于你能够镇静而又激动的欣赏这过程的美丽与悲壮 —— 24.8.31 一、正则表达式简介 正则表达式是描述字符模式的对象。正则表达式用简单的API对字符串模式匹配及检索替换,是对字符串执行模式匹配的强大工具。 1.语法 var pattnew RegExp(pattern,modi…

DataWorks数据质量监控方案

背景 日常的调度监控,可以查看实例任务的运行情况,对运行失败的实例进行告警,但是却无法对运行成功的实例进行数据质量的判断。而有些情况下,即使实例任务运行成功了,数据也仍然存在问题,这时候就需要对数…

uniapp / uniapp x UI 组件库推荐大全

在 uniapp 开发中,我们大多数都会使用到第三方UI 组件库,提起 uniapp 的UI组件库,我们最常使用的应该就是uview了吧,但是随着日益增长的需求,uview 在某些情况下已经不在满足于我们的一些开发需求,尽管它目…

第66期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

DOCKER(国内镜像源,安装相关微服务组件,py以及jar包的docker打包(上传私有云以及输出本地文件))

前言 之前单独在旧的帖子下面更新的时候,码字码了1000多字的时候电脑蓝了,重启什么东西都没有,我红了。平台上面的自动保存是针对新文章的。 这周因为隔壁有项目要验收了,我的好大哥就把我派过去配合赶进度了,还体验了…

java fastxml json 科学计数法转换处理

背景: 由于 canal 切换为 tx dbbridge后,发现dbbridge对于canal的兼容性存在较大问题,从而引发 该文档的实践。 就目前发现 dbbrige 的字段 大小写 和 数据类型格式 从binlog 写入kafka 同canal 都会存在差异。 canal之前导出都是小写&…

【ArcGIS/GeoScenePro】Portal和Server关系

简介 以下是ArcGIS的整体架构图 上图简化后 从图中我们可以看出可以将其分为三层其中: 最上层:应用层 中间层(门户):连接应用层和服务器,对server上发布的服务进行管理、分享和权限分配 最低层:服务器(Server层) 其中Enterprise = portal(中间层)+server(最底…

Tomato靶场渗透测试

1.扫描靶机地址 可以使用nmap进行扫描 由于我这已经知道靶机地址 这里就不扫描了 2.打开网站 3.进行目录扫描 dirb http://172.16.1.113 发现有一个antibot_image目录 4.访问这个目录 可以看到有一个info.php 5.查看页面源代码 可以发现可以进行get传参 6.…

3. GIS后端工程师岗位职责、技术要求和常见面试题

本系列文章目录: 1. GIS开发工程师岗位职责、技术要求和常见面试题 2. GIS数据工程师岗位职责、技术要求和常见面试题 3. GIS后端工程师岗位职责、技术要求和常见面试题 4. GIS前端工程师岗位职责、技术要求和常见面试题 5. GIS工程师岗位职责、技术要求和常见面试…

表连接查询之两个left join与递归SQL

一、如下SQL1 SELECT i.*,su1.name as createName,su2.name as updateNameFROM information ileft join sys_user su1 on su1.idi.create_idleft join sys_user su2 on su2.idi.update_id 二、分析 1、SELECT i.*,su.name as createName,sua.name as updateName FROM informati…

深度学习特征提取魔改版太强了!发文香饽饽!

要说CV领域经久不衰的研究热点,特征提取可以占一席,毕竟SLAM、三维重建等重要应用的底层都离不开它。 再加上近几年深度学习兴起,用深度学习做特征提取逐渐成了主流,比传统算法无论是性能、准确性还是效率都更胜一筹。 目前比较…

汽车制造商设备运维案例

汽车产线有很多传动设备需要长期在线运行,会出现老化、疲劳、磨损等问题,为了避免意外停机造成损失,需要加装一些健康监测设备,监测设备运行状态。天津三石峰科技采用无线温振传感器汇聚网关方案,将现场设备数据数据上…

linux~~目录结构远程登录教程(xshell+xftp)

目录 1.目录结构 2.远程登录xshell 2.1所需工具 2.2了解虚拟机IP 2.3查看是否正常连接 2.4xshell进行连接 3.文件传输xftp7 3.1xftp6安装 3.2相关设置 3.3效果展示 3.4文件之间的传输过程 1.目录结构 bin目录里面主要存放这个我们经常使用的指令,例如这个…

科研绘图系列:R语言PCoA图(PCoA plot)

介绍 PCoA(主坐标分析,Principal Coordinate Analysis)是一种多维数据的降维技术,它用于探索高维空间中样本之间的关系。PCoA通常用于生态学、遗传学和其他领域的数据分析,以揭示样本或个体之间的相似性或差异性。 PCoA图的作用: 数据降维:PCoA可以将高维数据(如物种…

RKNPU2从入门到实践 ---- 【8】借助 RKNN Toolkit lite2 在RK3588开发板上部署RKNN模型

前言 作者使用的平台为Ubuntu20.04虚拟系统,开发板为瑞芯微RK3588,开发板上的系统为Ubuntu22.04系统。 一、任务 完成RKNN模型的部署,RKNN模型的部署是将RKNN模型放到开发板上,应用程序可以加载RKNN模型,从而在嵌入式…

Markdown 语法大全详解

Markdown 语法大全详解 Markdown是一种轻量级标记语言,排版语法简洁,让人们更多地关注内容本身而非排版。它使用易读易写的纯文本格式编写文档,可与HTML混编,可导出 HTML、PDF 以及本身的 .md 格式的文件。因简洁、高效、易读、易…

Node.js模块系统

大家好呀,今天我们来认识以下Node.js的模块系统。 模块系统 目录 模块系统 node项目 创建一个完整的node项目 模块之间的引用 模块的导入 模块的分类 核心模块的引用 获取模块的导出对象 小结 node项目 一个node项目,单有JS文件是不行的&#xff…

Linux操作系统中的进程查看与进程调度

一.进程查看 什么是进程? 进程 process 计算机执行任务的最小单位,在计算机上运行一个应用软件可能会产生多个进程, 二.进程查看——ps -aux ps命令查看进程 如上图所示,是ps命令加上aux选项产生的结果,其作用是…

数字芯片中I/O单元及电源domain布局中SIPI的考虑

芯片设计的物理实施过程通常也简称为布局布线(P&R,Place-and-Route),布局一般被分为布局规划(Floorplan)和标准单元摆放(Place)两个过程。而其中的布局规划是芯片后端物理实现过…