当前位置: 首页 > news >正文

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本质都是类,都存在缓冲区,我们将这种语言级别的缓冲区称作字节流,读写都是从字节流中获取。

相关文章:

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

目录 文件描述符 基础知识 文件描述符 对“Linux一切皆文件”的理解 文件描述符分配规则 缓冲区 刷新策略 存放位置 解释一个"奇怪的现象" 格式化输入输出 文件描述符 基础知识 在系统层面上,文件操作都是通过文件描述符来操作的。 程序在启…...

云计算实训39——Harbor仓库的使用、Docker-compose的编排、YAML文件

一、Harbor部署 1.验证python版本 [rootdocker2 ~]#python --version 2.安装pip [rootdocker2 ~]# yum -y install python2-pip #由于版本过低,需要对其进行一个升级 #更新pip [rootdocker2 ~]#pip install --upgrade pip 3.指定版本号 [rootdocker2 ~]# p…...

lambda表达式用法——C#学习笔记

“Lambda 表达式”是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。 实例如下: 代码如下: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.…...

【C++ Primer Plus习题】11.6

问题: 解答: main.cpp #include <iostream> #include "Stonewt.h" using namespace std; const int SIZE 6;int main() {Stonewt stone_arr[SIZE] { 253.6,Stonewt(8,0.35),Stonewt(23,0) };double input;Stonewt eleven Stonewt(11, 0.0);Stonewt max st…...

Redis八种数据结构简介

Redis数据结构 Redis新旧版本中一共出现过八种数据结构&#xff0c;分别是SDS、双向链表、压缩列表、整数集合、哈希表、跳表、quicklist、listpack。 SDS SDS是用于存储Redis中字符串的数据结构&#xff0c;Redis底层使用的语言是C语言&#xff0c;因此字符串也是C语言的字…...

数据治理策略:确保数据资产的安全与高效利用

数据治理策略&#xff1a;确保数据资产的安全与高效利用 在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。然而&#xff0c;随着数据量的爆炸性增长和数据来源的多样化&#xff0c;如何有效地管理和利用这些数据成为企业面临的重要挑战。数据治理策略的制定和执行&a…...

ts格式转mp4,四款亲测好用软件推荐!

在这个数字视频时代&#xff0c;我们经常会遇到各种视频格式兼容性问题&#xff0c;尤其是从网络下载的高清电影或电视剧集&#xff0c;很多时候都是以TS格式存储。然而&#xff0c;当我们想要在移动设备、社交媒体或视频编辑软件中播放、上传时&#xff0c;MP4格式因其广泛的兼…...

10、Django Admin修改标题

admin from django.contrib import admin from .models import Category, Origin, Hero, Villain # 添加以下代码 admin.site.site_header "系统管理" admin.site.site_title "管理员界面" admin.site.index_title "欢迎来到这里&#xff…...

ESRI ArcGIS Pro 3.1.5新功能及安装教程和下载

ESRI ArcGIS Pro 3.1.5 主要新功能包括&#xff1a; 改进的数据编辑和管理&#xff1a;支持更多数据格式和更精细的属性表操作。增强的空间分析工具&#xff1a;新增和优化空间分析工具&#xff0c;提高数据分析效率。更好的3D可视化&#xff1a;改进3D渲染性能&#xff0c;支…...

人工智能,语音识别也算一种人工智能。

现在挺晚了&#xff0c;还是没有去睡觉&#xff0c;自己在想什么呢&#xff0c;也不确定。 这是一篇用语音写的文章&#xff0c;先按自己的想法说出来&#xff0c;然后再适当修改&#xff0c;也许就是一个不错的文章。 看来以后就不需要打字了&#xff0c;语音识别度很高&#…...

Token和Refresh Token

获取令牌&#xff08;Token&#xff09; 和 刷新令牌(Refresh Token&#xff09; 在认证和授权机制中有不同的使用场景和目的&#xff0c;二者主要的区别和为什么需要刷新令牌可以通过以下几点解释&#xff1a; 1. 获取令牌和刷新令牌的区别 获取令牌&#xff08;Token&#x…...

STM32(一)简介

一、stm32简介 1.外设接口 通过程序配置外设来完成功能 2.系统结构 3.引脚定义 4.启动配置 5.最小系统电路...

接口测试工具:Postman详解

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、前言 在前后端分离开发时&#xff0c;后端工作人员完成系统接口开发后&#xff0c;需要与前端人员对接&#xff0c;测试调试接口&#xff0c;验证接口的正确性…...

Linux中全局变量配置,/etc/profile.d还是/etc/profile

全局环境变量可以放在 /etc/profile 或 /etc/profile.d/ 中&#xff0c;但两者的使用方式和目的有所不同&#xff1a; /etc/profile 作用: /etc/profile 是一个系统范围的启动脚本&#xff0c;在用户登录时执行。它主要用于设置全局环境变量和配置&#xff0c;适用于所有用户。…...

【java入门】关键字、标识符与变量初识

&#x1f680; 个人简介&#xff1a;某大型国企资深软件开发工程师&#xff0c;信息系统项目管理师、CSDN优质创作者、阿里云专家博主&#xff0c;华为云云享专家&#xff0c;分享前端后端相关技术与工作常见问题~ &#x1f49f; 作 者&#xff1a;码喽的自我修养&#x1f9…...

Java常用类库

Java常用类库 1. **Java基础类库**1.1 **java.lang**1.2 **java.util**1.3 **java.io**1.4 **java.nio**1.5 **java.time** 2. **第三方类库**2.1 **Apache Commons**2.2 **Google Guava**2.3 **Jackson**2.4 **Lombok** 3. **Spring相关类库**4. **并发类库**4.1 **java.util.…...

2024年高教社杯数学建模国赛C题超详细解题思路分析

本次国赛预测题目难度&#xff0c;选题人数如下所示 难度评估 A:B:C 1.8:1.3:1 D:E1.5:1 选题人数 A:B:C 1:1.5:2.8 D:E0.5:1.2 C题一直以来都是竞赛难度最低、选题人数最多的一道本科生选题&#xff0c;近三年C题的选题人数一直都是总参赛队伍的一半左右&#xff0c;2023年…...

深度学习(七)-计算机视觉基础

计算机视觉 计算机视觉在广义上是和图像相关的技术总称。包括图像的采集获取&#xff0c;图 像的压缩编码&#xff0c;图像的存储和传输&#xff0c;图像的合成&#xff0c;三维图像重建&#xff0c;图像增强&#xff0c;图像修复&#xff0c;图像的分类和识别&#xff0c;目…...

机器人笛卡尔空间轨迹规划原理与MATLAB实现

机器人笛卡尔空间轨迹规划是指在给定的笛卡尔坐标系&#xff08;通常是三维空间坐标系&#xff09;中规划机器人的末端执行器&#xff08;如抓手、焊枪等&#xff09;的移动路径。这种规划方式直观且易于理解&#xff0c;因为它直接关联到任务空间中机器人的位置和姿态。下面将…...

数据结构:树与二叉树

1、树的基本概念 1.1树的定义 树是n个结点的有限集。 若n0&#xff0c;称为空树&#xff1b;若n>0称为非空树&#xff0c;非空树有且仅有一个称之为根的结点。 除根结点以外的其余结点可分成m个互不相交的有限集T1,T2,......Tm,每个有限集合本身又是一棵树&#xff0c;并…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...

Spring Security 认证流程——补充

一、认证流程概述 Spring Security 的认证流程基于 过滤器链&#xff08;Filter Chain&#xff09;&#xff0c;核心组件包括 UsernamePasswordAuthenticationFilter、AuthenticationManager、UserDetailsService 等。整个流程可分为以下步骤&#xff1a; 用户提交登录请求拦…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...