【进程IO】详细讲解文件描述符fd

news2024/11/27 14:45:45

文章目录

  • 前言
  • 什么叫文件描述符
    • FILE与fd的关系
  • 再次理解文件
    • 为什么要有文件的方法列表呢?
  • 进程和struct file的关系
  • 再次理解open操作

前言

C语言的关于文件操作的各种函数实际上是对系统调用的封装。那么从进程的角度看,一个文件到底是如何被描述的呢?又是如何被组织并管理的呢?
在此之前,如果对C语言以及系统调用关于文件相关内容的知识还不太了解或许需要复习的同学,可以去看我之前的博客:
C语言关于文件概述以及文件操作
关于文件的系统调用

什么叫文件描述符

所有的I/O设备都被模型化为文件,而所有的输入输出都被当成对文件的读写操作。这种将设备优雅地映射为文件的方式,允许Linux内核引出一个简单的,低级的应用接口,成为Unix I/O,着使得所有的输入输出都能以一种统一切一致的方式来执行,这也是为什么说linux下一切皆文件。

当程序通过要求内核打开相应的文件。内核会返回一个小的非负整数。这个非负整数就叫做描述符,也叫文件描述符。文件描述符是用于唯一标识文件的号码。下面我用fd表示文件标识符。

也就意味着,我们的进程实际上并不记录文件本身,而只需要记录一个为一个文件ID。所有被打开的文件的信息都被集中在一起被内核管理,内核向进程提供文件的接口。

在这里插入图片描述
尝试打开多个文件并观察其文件描述符:
在这里插入图片描述

在这里插入图片描述
我们发现打开的文件其ID是从3开始的,这是属于巧合吗?
其实并不是
Linux shell 创建的每一个进程开始的时候都有三个打开的文件:标准输入流(fd=0),标准输出流(fd=1),标准错误流(fd=2)。这三个文件分别对应的硬件设备是键盘、显示器、显示器。

在c语言中也会默认给我们打开三个文件
在这里插入图片描述
如何证明这三个文件会默认打开呢?
在这里插入图片描述

在这里插入图片描述

对于以上结果,我们可以直接在stdout文件里写入数据,说明了stdout文件确实是被默认打开了!

再证明stdout文件的描述符是1,看代码:
在这里插入图片描述
在这里插入图片描述
这里使用系统调用的write函数直接向文件描述符为1的文件写入数据。我们发现文件标识符1指的就是stdout文件。由此,证明了进程会默认打开stdout文件,并且该文件的fd=1.其余两个文件也是同样的道理。

FILE与fd的关系

FILE是C语言用来描述文件的一个结构体,在了解了文件描述符之后,我们其实也能明白FILE的底层实现了对fd的封装

再次理解文件

以用户的视角来看,文件=属性+内容。以操作系统的视角来看,文件其实就是一个名为filestruct

每当我们打开一个文件,操作系统就会生成一个struct file记录该文件的所有信息,包括以何种方式打开,文件的标记位等。并将这个file以双链表的形式加入到所有打开文件的集合中,这个集合统一由操作系统管理

其中值得我们关注的是,struct file内部会包含一个指针,指向该文件的内核级缓存区。进程就是在这个区域里面进行读写数据。该区域的存在避免了进程直接向磁盘读写数据,提高了效率(缓冲区存在的意义)。
在这里插入图片描述
除此之外,struct file里还含有文件的类型以及该文件的方法列表。方法列表包括了open方法,write方法等。

为什么要有文件的方法列表呢?

首先所有的硬件都有一定的存储能力。这也就意味着我们能以看待磁盘的视角来看待其他硬件。比如显示器,键盘等。我们所说的什么键盘文件其实就是用来跟键盘的存储空间打交道的不同硬件读写数据的操作方法可能不一样。比如键盘文件就没有向其写数据的方法,我们只能从键盘读取而不能写入
所以方法列表中的元素其实就是一个函数指针,指向对应硬件的读写方法。
虽然各个硬件中的读写方法存在差异,但是相同功能的函数名字可以一致。
这样操作系统就能以统一的视角来看待各个硬件的读写方法。

进程和struct file的关系

一个进程可以打开多个文件,对于进程来说,被打开的文件同样也算是一种资源。
为了区分一个进程拥有的“打开文件”集合。操作系统为每个进程建立了一张
struct files_struct表,表中有一个struct file*数组fd_array,这个数组就指向该进程所有的打开的文件。task_struct中的 struct files_struct* files指针就指向这张表。
在这里插入图片描述

fd_array是文件映射关系数组。fd_array数组中的每个元素都是对应操作系统管理文件集合中的某个文件。于是我们就能通过下标访问该数组,从而在操作系统管理文件集合中找到目标文件

非常合理的,文件描述符就是fd_array数组的下标!!!
这样我们也就明白了,文件操作的系统调用为什么是用fd来做参数的。因为我们能通过fd准确地找到目标文件。

再次理解open操作

在明白文件是如何被描述以及如何被管理之后,我们也就能更加深刻的理解系统调用open打开文件的过程:

1.创建struct file(包括fd)
2.开辟文件缓存区,加载文件中的数据(延后)
3.查进程的文件描述符表(fd_array数组)
4.将file的内存地址填入到fd_array[fd]中
5.返回fd.

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

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

相关文章

Postwoman 安装

Postwoman作为Postman的女朋友,具有免费开源、轻量级、快速且美观等特性,是一款非常好用的API调试工具。能帮助程序员节省时间,提升工作效率。 Github地址:GitHub - hoppscotch/hoppscotch: 👽 Open source API devel…

Qt/QML编程之路:画线及倒车影响(48)

前言: 倒车影像中有一个属性比较实用,那就是倒车线,这条线很明显会在视频图像上叠加显示,或者说在视频上面一个图层画的线。这里有一个画线的Qt示例,用于在一个scene上画一个对角线: #include "mainwindow.h" #include <QApplication> #include <QtW…

ES6 学习(一)-- 基础知识

文章目录 1. 初识 ES62. let 声明变量3. const 声明常量4. 解构赋值 1. 初识 ES6 ECMAScript6.0(以下简称ES6)是JavaScript语言的下一代标准&#xff0c;已经在2015年6月正式发布了。它的目标&#xff0c;是使得」JavaScript语言可以用来编写复杂的大型应用程序&#xff0c;成为…

关系网络c++

题目&#xff1a; 代码&#xff1a; #include<bits/stdc.h>using namespace std;int n,x,y;struct node{int num;//编号 int t;//步数 node(){}node(int sum,int tt){numsum;ttt;} }; int mp[101][101];//图 bool flag[101];//标记 queue<node> q; void bfs() {q…

FLASH的读取与写入

FLASH的写入 结合HAL库所给参数&#xff1a; 查阅具体使用芯片的参考手册。 就不在详细解释&#xff0c;英文自行翻译。具体代码如下&#xff1a; /*FLASH写入程序*/ void WriteFlashTest(uint32_t L, uint32_t addr, uint32_t *Data,int Page) {int i0;/* 1/4解锁FLASH*/HAL…

【Anaconda】Linux下Anaconda安装和虚拟环境配置

Linux下Anaconda安装和虚拟环境配置 一、安装anaconda二、conda虚拟环境管理三、jupyter相关启动部署四、遇到问题 下面介绍整体流程&#xff0c;遇到问题优先看“遇到问题章节”&#xff01; 一、安装anaconda 1.下载anaconda安装包 &#xff08;1&#xff09;可以选择在官网…

文件名目录名或卷标语法不正确:数据恢复策略与预防措施

一、文件名目录名或卷标语法不正确的现象 在日常使用电脑或移动设备时&#xff0c;我们经常会遇到“文件名目录名或卷标语法不正确”的错误提示。这种错误通常发生在尝试访问、修改或删除文件、目录或卷标时&#xff0c;系统会提示无法完成操作&#xff0c;因为文件名、目录名…

JavaScript高级 —— 学习(二)

目录 一、深入对象 &#xff08;一&#xff09;创建对象三种方式 1.利用对象字面量创建 2.利用 new Object() 创建 3.利用构造函数创建 &#xff08;二&#xff09;利用构造函数创建对象 1.构造函数介绍 2.约定 3.实例化执行过程 &#xff08;三&#xff09;实例成员…

动态规划之子序列(一)

300.最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序…

Oracle数据库——子查询五

14.1子查询语法 子查询 (内查询) 在主查询之前一次执行完成。子查询的结果被主查询(外查询)使用 。范例一:谁的工资比 Abel 高? 第一:查询Abel的工资是多少。第二:比较大于这个工资的人数。 注意事项: 子查询要包含在括号内。将子查询放在比较条件的右侧。</

docker部署-RabbitMq

1. 参考 RabbitMq官网 docker官网 2. 拉取镜像 这里改为自己需要的版本即可&#xff0c;下面容器也需要同理修改 docker pull rabbitmq:3.12-management3. 运行容器 docker run \ --namemy-rabbitmq-01 \ -p 5672:5672 \ -p 15672:15672 \ -d \ --restart always \ -…

基于opencv的SVM算法的车牌识别系统设计与实现

基于opencv的SVM算法的车牌识别系统设计与实现 车牌识别技术是智能交通系统中的一项关键技术&#xff0c;它能够自动识别车辆的车牌号码。本文将详细介绍如何使用Python编程语言结合OpenCV库和SVM算法来实现车牌识别系统。 系统架构 车牌识别系统主要包括以下几个模块&…

STM32的简介

内存 一般MCU包含的存储空间有FLASH和RAM,&#xff08;RAM和flash又有片上和片外的区别&#xff0c;片上表示mcu自带的&#xff0c;已经封装在MCU内部的&#xff0c;片外表示外挂的&#xff0c;当项目中需要做一些复杂的应用&#xff0c;会存在资源不足的情况&#xff0c;这时…

【C语言】贪吃蛇【附源码】

欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 一、游戏说明&#xff1a; 一个基于C语言链表开发的贪吃蛇游戏&#xff1a; 1. 按方向键上下左右&#xff0c;可以实现蛇移动方向的改变。 2. 短时间长按方向键上下左右其中之一&#xff0c;可实现蛇向该方向的短时间…

flutter生成二维码并截图保存到图库

引入库&#xff1a;flutter_screenutil、image_gallery_saver、qr_flutter弹窗布局 import dart:async; import dart:typed_data; import package/generated/l10n.dart; import package:jade/configs/PathConfig.dart; import package:jade/utils/ImageWaterMarkUtil.dart; im…

三、强一致性介绍

这里写自定义目录标题 三、强一致性介绍3.1 基本理解3.2 DTP模型3.3 落地协议XA3.4 ⼆阶段提交模型3.5 ⼆阶段提交的问题3.6 navicat操作xa 三、强一致性介绍 3.1 基本理解 相关特点 强⼀致性解决⽅案要求在任何时间点&#xff0c;任何时刻查询&#xff0c;参与全局事务的各个…

ROS 2边学边练(7)-- 何为动作(actions)

概念 我们先来看一张动图&#xff0c;下文再围绕这张图对动作作简单阐释和说明。 如上图所示&#xff0c;动作的复杂度比之前提到的几种通信方式&#xff08;主题、服务&#xff09;要大一点&#xff0c;但是几者之间也有着千丝万缕的关系&#xff0c;动作糅合了主题和服务的机…

【MySQL】DQL-排序查询-语法&排序方式&注意事项&可cv例题语句

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

常用技术-Stream流

目录 Stream流是什么&#xff1f; 认识Stream流 流和集合的区别 Stream流的操作 中间操作 Filter(过滤) Map(转换) Sorted(排序) Distinct(去重) Limit(限制) Skip(跳过) Peek(展示) 终止操作 forEach(循环) Collect(收集) Count(计数) Reduce(聚合) 使用Strea…

我爱DFS序列搜索

什么是DFS&#xff1f; DFS算法&#xff0c;即深度优先搜索&#xff08;Depth-First Search&#xff09;算法&#xff0c;是一种用于遍历或搜索图或树的算法。DFS算法可以解决诸如路径查找、图的连通性、拓扑排序以及树结构中的深度遍历等问题。然而&#xff0c;需要注意的是&…