文件与fd

文件与fd

  • 一、前置预备
  • 二、复习c语言文件
  • 三、系统文件认识
    • 3.1 系统层面有关文件的接口(open):![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b15577967d1445b08cd5252f2009683a.png)
    • 3.2 简单使用open参数
    • 3.3 语言vs系统
    • 3.4 进一步理解文件描述符:
  • 四、内核中的文件
    • 4.1 初步了解
    • 4.2 理解一切皆文件:
    • 4.3 IO基本过程
    • 4.4 重定向

一、前置预备

在这里插入图片描述

1、首先我们先回忆一下,在linux的前几章,文件=内容+属性(时间等属性)
2、在c语言中使用文件的形式是固定的—先打开文件,然后操作文件,最后关闭文件,那为什么在访问文件之前我们必须先打开它了?
(1)首先我们需要知道文件没有被打开时存放在哪里?----一般来说文件都存放于磁盘
(2)那是谁在访问文件?----是不是当前我们写的代码所编译形成的程序啊,这个程序我们也可以称为一个进程
(3)既然是进程来访问我们的文件,那根据我们前面所学的知识,进程是不是需要被加载到内存中然后被cpu来执行,当进程运行到打开文件这一行代码时,cpu能够直接去读取磁盘上的文件吗?—很显然是不能的(冯洛伊曼),所以打开文件本质上就是文件加载到内存当中,那我们可以类比一下,进程被加载到内存时,进程=内核数据结构+代码、数据,文件是不是可以认为,文件=内核数据结构+文件内容
3、结论:我们研究打开的文件,是在研究:进程和文件的关系
4、研究文件系统可以分为两部分来学习:
(1)没有被打开的文件(磁盘)
(2)被打开的文件(内存)

二、复习c语言文件

1、在c语言或者c++中,一个进程会默认打开3个文件,就是标准输入输出流和错误流,对应的就是键盘、显示器。但是我们知道键盘和显示器都是硬件设备,我们能够直接通过程序访问硬件设备吗?—很显然不能,原因后面讲解。(stdin / stdout / stderr)
2、是谁默认打开这三个标准输入输出流?----进程

下面就是c语言中对文件的两种操作方式:
在这里插入图片描述

1、w(只写),Truncate file to zero lengh or create text file for writing.(>)
(1)没有该文件,创建该文件,并且写入
(2)有该文件,但是没有对文件写入,则清空
(3)有该文件,并且有写入,从0位置覆盖式写入
在这里插入图片描述

2、a(追加),顾名思义不会清空该文件内容,而是从结尾继续添加写入的内容(>>)
在这里插入图片描述

3、我们有几种打印到屏幕的方式?:(纯C)
在这里插入图片描述
4、我们知道用户是不能直接访问硬件的(磁盘,显示器,键盘),要想访问必须经过OS,所以我们所使用的C文件接口,底层一定封装了对应的文件类系统调用

三、系统文件认识

在c语言或者c++中,文件的操作其实是给我们封装好的,我们调用语言内的函数,然后它又调用系统接口,那我们现在就来看一下系统中文件的接口

3.1 系统层面有关文件的接口(open):在这里插入图片描述

open中的参数:
(1)pathname:文件的文件名
(2)flags:常见的打开方式
O_RDONLY(只读)、 O_WRONLY(只写)、O_RDWR(读写),O_TRUNC(存在该文件就清空)、
O_CREAT(创建)、O_APPEND(若文件操作,追加),这些打开方式本质上是宏
第二个位置的操作方式可以传多个,但是一般来说系统的接口是c语言的,不支持可变参数,这里是通过位图的方式实现的,下面我们通过简单的代码来看下位图是如何控制标记位的
在这里插入图片描述
(3)mode:权限位,在系统中文件管理与权限管理是两个不同的模块,如果文件已经存在,第三个参数没有影响,但是如果我们是打开一个新的文件时,会创建一个新的文件,如果不带第三个参数,那么该文件的权限是乱码。
(4)系统中的open调用是有返回值的,它的返回值类型为int,当文件操作失败返回-1,正常操作返回 !0,我们一般称这个返回值叫做文件描述符。

在这里插入图片描述
由上图我们可以看到,本质上系统中文件调用的接口只有两个,两个接口差别很微小,只有第三个参数的差别。(如果文件不存在,我们建议使用三参数open,如果文件已经存在则建议使用两参数open)

3.2 简单使用open参数

1、打开文件:
在这里插入图片描述
这里的umask不会改变系统的umask

2、touch的简单实现:
在这里插入图片描述

3、关闭文件(close),读(read),写(write),
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

综合使用文件接口:
在这里插入图片描述

3.3 语言vs系统

在这里插入图片描述
总结:语言上的fopen就是封装的系统调用接口

3.4 进一步理解文件描述符:

在这里插入图片描述

1、文件描述符我们可以简单的理解为该文件在当前程序操作的所有文件中的序号,一般来说我们打开的文件默认从3开始,因为系统默认打开了三个文件,stdin(0),stdout(1),stderr(2)。
在这里插入图片描述

2、字符串以\0结尾是c语言的规定,跟文件无关,所以写文件时只写字符长度,如果写的时候让长度+1,也就是想将\0也写入,这个时候系统会默认\0为乱码

四、内核中的文件

4.1 初步了解

上面我们简单的介绍了系统中的文件调用,现在我们来理解一下内核中的文件:
在这里插入图片描述
1、在文件没有启动时它是以内容+属性的形式存储于磁盘空间内部
2、文件被打开是进程(task_struct)来打开的,也就是文件加载到内存中(创建struct file)
3、进程被CPU调度时会调用open系统调用
4、在内存中存在很多个struct file的结构体对象,它管理着文件的打开属性,系统默认会打开3个文件(键盘,显示器,显示器),在OS层面上,有一个file list将所有结构体链接起来,对文件的管理,变成了对链表的增删查改
5、进程也是由一个链表链接起来管理的(task_struct)
6、进程链表管理进程,file链表管理文件,OS层面是解耦合的,(一个进程-----多个文件)为了让两者相关联,PCB内部存在一个指针(struct files_struct* files),OS会为每个进程里的该指针创建一个struct files_struct的结构体,其中会存在一个叫做struct file* fd_array[N]的数组(指针数组)
7、上面这个数组中下标对应的位置直接连接文件的结构体
8、文件描述符本质上是数组下标,进程和文件用指针来相关联
9、OS层面,fd是唯一访问文件的方式,FILE是C提供的访问文件的结构体,它会有很多的属性 --(其中有一个属性必定对fd做封装)
在这里插入图片描述
在这里插入图片描述

4.2 理解一切皆文件:

在这里插入图片描述
1、之前我们说过每一个硬件都有一个共同的名字叫做外设,我们如果整体来看的话可以发现所有设备可以拥有相同的属性类别,但是属性具体的值可以不一样,怎么理解呢?例如:设备号,状态值等,所以我们是可以将所有的外设用一个结构体去描述的,现在我们要访问键盘、网卡、磁盘以及显示器,对上述设备的访问的方式一定是不同的,例如键盘只能读,显示器只能写,那这个结构体怎么才能将所有设备统一呢?

2、在外设的角度上,所有的设备都其实实现了read和write方法,但上面我们刚说有些外设只需要其中一种,这个不必担心,需要的方法我们不去实现它即可

3、站在linux操作系统上,对一个文件进行操作之前,我们都会创建一个struct file,这个结构体里会有一系列的调用外设的方法,我们来介绍其中最典型的两个,就是
int (*read) ();
int (*write) ();

操作系统通过函数指针的形式来访问外设的操作函数,如此现在我们就不需要关心键盘、网卡、显示器、、、的具体函数实现,我们只需要调用接口即可,这一套机制我们称为vfs(虚拟文件系统)

4、在struct file中又会提供文件描述符,所以我们对文件的操作转化到了对文件描述符上的操作,系统调用也是通过对这些函数指针操作的

5、上面介绍的这种上层的struct file与外设的struct device这种技术实际上就是多态的实现原理
在这里插入图片描述文本写入 vs 二进制写入
在这里插入图片描述
1、我们需要明白显示器显示12345,这里到底是一个整数还是5个数字字符?–其实这里显示器显示的是5个字符,所以实际上我们编写的代码中输出所有整数类型,系统都会先转化为字符,然后再在显示器打印,系统就觉得太麻烦了,每次都需要我们自己转换,并且我们写的可能还会出现许多问题,故此系统封装了一系列函数

2、c语言中的scanf与printf它叫做格式化输入与输出,它的作用就是将文件内的内容以固定格式来输入输出,其次计算机所谓的文本与二进制其实没有本质差别,不管我们输入的是字符,数字,符号,本质上计算机都是以二进制处理的,例如可执行文件,我们要知道可执行文件会被编译成二进制,我们向二进制文件输入文件,它会认识吗?

3、那为什么c、c++还会封装一系列函数呢?这是因为虽然系统给我们做了一层封装,但是要是换系统了呢?上面我们都是基于linux系统来谈的,封装的好处就是语言的可移植性

4、为什么我们使用c语言的库函数在linux或者win下都可以随便使用?这是因为这些库函数的代码其实全部都封装在库内(glic)当我们需要调用库内的函数时,系统会将该函数编译成当前系统的版本,例如win版,linux版。所以在使用一门语言时,需要先安装环境,安装环境就是安装库
在这里插入图片描述

4.3 IO基本过程

1、input:当我们调用write函数时,我们通过文件描述符找到了文件操作表,又在文件操作表中通过函数指针调用写的操作,但我们写的内容并不是直接就写入硬盘的,而是先写入文件内核缓冲区,再刷新至硬盘文件空间,刷新是由os自主决定,意识是指缓冲区有多少内容或者多少时间执行一次刷新,由操作系统来决定
2、output:与上面的操作相反,但也是现将硬盘上的文件内容拷贝至缓冲区,然后os自主决定刷新

缓冲区(系统)的存在是因为内存的操作速度太快了,外设的操作速度非常的慢(例如我们要进行IO操作,如果没有缓冲区,我们每进行一个字符的操作就都要进行一次外设的访问,效率太低了,但现在我们有了缓冲区,也就是说我们现在可以向缓冲区写入100或者1000的数据然后进行一次写入写出,效率大大的提升了),同时系统也会进行预加载,进一步提升IO地效率
所以write与read本质上是拷贝函数。

在这里插入图片描述

4.4 重定向

1、fd的分配规则:进程打开文件,需要给文件分配新的fd(最小的,没有被使用的),如果系统默认的0,1,2被关闭,系统也会将0,1,2分配出去

在这里插入图片描述
1、在上面的代码中如果没有关闭1,这个文件的话,会默认打印3,4,5,6在显示器上,这也符合我们的预期,但当我们关闭1后,本来应该向显示器打印的内容,却写入到了log1.txt文件中,这是为什么呢?
这是因为printf函数默认会向stdout这个文件打印,我们知道printf也是通过文件描述符去操作文件的,但是printf只认1这个文件描述符,但此时1这个文件描述符已经被log1.txt给占用了,所以现在的操作变为了向log1.txt写入了

所谓的重定向就是系统只认0,1,2,但是现在我们让特定文件描述符内的内容做出修改,而系统毫不知情
系统的中重定向接口叫做dup2

在这里插入图片描述
系统实现重定向的方式非常简单,0,1,2这三个位置本质上是指针数组,我们现在让数组内3号位置的指针,拷贝到1号位置,这就是输出重定向,这一些列操作都必须使用系统调用也就是dup2(oldfd,newfd)
例如输出重定向就是dup2 (fd,1);
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

语义通信高斯信道仿真代码

1️⃣ 代码 def AWGN(coding, snr, devicecpu):"""为输入张量添加高斯白噪声(AWGN),根据指定的 SNR(分贝)控制噪声强度。参数:coding (torch.Tensor): 输入张量,形状为 [batch_s…

unity中实现机械臂自主运动

目的:导入机械臂的fbx模型,利用C#编写脚本实现机械臂的自主运动步骤1.在 Unity 中,右键点击 “Assets” 文件夹,选择 “Create” -> “C# Script” 来创建一个新的 C# 脚本命名为 “ArmController”。2.双击打开脚本&#xff0…

Python 版本与 package 版本兼容性检查方法

网罗开发(小红书、快手、视频号同名)大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方…

深入剖析分布式事务的Java实现:从理论到Seata实战

文章目录深入剖析分布式事务的Java实现:从理论到Seata实战引言:分布式事务的现实挑战1. 分布式事务理论基础1.1 从ACID到CAP/BASE1.2 典型业务场景分析2. 主流分布式事务解决方案对比2.1 技术方案全景图2.2 选型建议3. Seata框架深度解析3.1 Seata架构设…

自建知识库,向量数据库 (十一)之 量化对比余弦——仙盟创梦IDE

向量比对:开启企业经营自动化搜索新视野在当今数字化时代,企业经营自动化已成为提升竞争力的关键。其中,搜索功能作为企业获取信息、连接用户与资源的重要入口,其效率和准确性直接影响企业的运营效率和用户体验。向量比对在企业经…

Spring Cloud系列—SkyWalking告警和飞书接入

上篇文章: Spring Cloud系列—SkyWalking链路追踪https://blog.csdn.net/sniper_fandc/article/details/149948321?fromshareblogdetail&sharetypeblogdetail&sharerId149948321&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目…

【问题】解决docker的方式安装n8n,找不到docker.n8n.io/n8nio/n8n:latest镜像的问题

问题概览 用docker方式安装n8n,遇到错误,安装不了的问题: Unable to find image docker.n8n.io/n8nio/n8n:latest locally docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request can…

机器人控制基础:串级PID控制算法的参数如何整定?

目录 一、整定前的准备 二、内环(副环)参数整定(核心步骤) 1. 断开主环,单独测试内环 2. 内环参数整定(按 “比例→积分→微分” 顺序) (1)比例系数(kp)整定 (2)积分系数(ki)整定 (3)微分系数(kd)整定(可选) 3. 验证内环抗扰动能力 三、外环(主…

HTTP性能优化实战指南(含代码/图表/案例)

HTTP性能优化实战指南(含代码/图表/案例)一、性能优化关键指标TTFB(Time To First Byte): 服务器响应时间FCP(First Contentful Paint): 首内容渲染时间LCP(Largest Contentful Paint&#xff0…

QT代码框架小案例:一个简单的时间类(Time)及其实例化程序,模拟了时间的设置、显示和自动流逝功能,类似一个简易电子时钟。

一、代码框架二、运行终端显示三、代码详细注释test.pro# 指定项目类型为应用程序(而非库或其他类型) TEMPLATE app# 配置项目:启用控制台输出,使用C11标准 CONFIG console c11# 移除配置:不生成应用程序捆绑包&…

Nacos-11--Nacos热更新的原理

在Nacos中,当监听到配置变化后,Nacos提供了相关机制(长轮询或gRPC)让客户端能够监听到配置的变化,并触发相应的监听器(Listener),但具体的处理逻辑需要根据实际需求来实现。 1、热更…

fastapi 的BackgroundTasks

什么是 BackgroundTasks?BackgroundTasks 是 FastAPI 提供的一个强大工具,它允许你将一些非紧急的、耗时的操作(例如发送邮件、处理数据、调用第三方 API 等)放到“后台”去执行,而不是让用户一直等待这些操作完成。它…

Python 十进制转二进制

在 Python 中,将十进制整数转换为二进制有多种方法。以下是几种常见的方式:1. 使用 bin() 函数bin() 是 Python 内置函数,可以将十进制整数转换为二进制字符串。语法bin(n)示例n 13 binary_str bin(n) print(binary_str) # 输出: 0b1101说…

合并工作表,忽略手动隐藏行超简单-Excel易用宝

同事小丽有一个工作簿,文件中有多个工作表,每个工作表中有多行数据,这些表格中数据是有手动隐藏行的,她想把这些表格的数据忽略隐藏行合并到一个工作表中,但是使劲浑身解数,各种折腾,都会把隐藏…

我从零开始学习C语言(14)- 基本类型 PART1

今天学习第7章-基本类型,主要内容如下:7.1 整数类型这里的整数的整数值就是数学意义上的整数。C语言支持两种本质上(存储形式)不同的数值类型:整数类型(简称整型)和浮点类型(简称浮点…

Flutter - UI布局

一、容器Widget1. ScaffoldScaffold 作为页面的脚手架,基础区域包含顶部导航栏 appBar、主体内容区 body、侧边抽屉 drawer、悬浮按钮 floatingActionButton、底部导航栏 bottomNavigationBar。Scaffold(appBar: AppBar( // 顶部导航栏title: Text(首页),),body: Ce…

UNIKGQA论文笔记

UNIKGQA: UNIFIED RETRIEVAL AND REASONING FOR SOLVING MULTI-HOP QUESTION ANSWERING OVER KNOWLEDGE GRAPH(ICLR 2023)Introduction知识图上的多跳问题回答(KGQA)的目的是在大规模知识图谱(KG)上找到自然语言问题中提到的主题实…

MySQL 8.0.17 “Too Many Connections” 排查指南

MySQL 8.0.17 “Too Many Connections” 排查与优化指南 在 MySQL 8.0.17 中,当出现“Too many connections”错误时,通常意味着数据库连接数已达上限。这不仅会影响应用性能,还可能导致连接池(如 Druid)无法获取新连接…

GEO优化服务:智能时代营销新赛道的中国引领者——全球行业格局与发展趋势观察

随着全球人工智能技术的迅猛发展,以GPT-5、Claude Opus以及我国的DeepSeek Divine、豆包等为代表的新一代生成式AI搜索引擎,正深刻改变着信息获取与商业决策模式。用户通过直接向AI提问获取整合答案的行为日益普遍,传统搜索引擎的流量入口地位…

全面解析主流AI模型:功能对比与应用推荐

全面解析主流AI模型:功能对比与应用推荐 在当前人工智能技术飞速发展的背景下,市面上涌现了多种具备不同能力的AI模型。本文将系统梳理主流模型的特性、对比其核心能力,并结合实际场景推荐高效、稳定的API服务(如https://api.aaa…