文件描述符表

news2024/11/28 14:05:15

文章目录

  • 1. 文件描述符
    • 1.1 前言
    • 1.2 理解文件
    • 1.3 文件描述附表
    • 1.4 打开文件时
    • 1.5 默认打开的三个文件
  • 2. 重定向
    • 2.1 瞅瞅
    • 2.2 dup2
    • 2.3 实现原理
  • 3. 一切皆文件

1. 文件描述符

1.1 前言

环境:Linux 2.6

在 Linux 中,有句话叫做「一切皆文件」,指的是在 Linux 中的设备,资源等几乎一切资源都抽象成了文件,然后只需要提供对文件进行操作的接口,就可以让我们用统一的方式来读取,写入等各种操作,从而来管理 Linux 中的各种资源和数据。这种设计模式不仅简化了 Linux 架构,还简化了开发人员对资源的操作

1.2 理解文件

当进程打开一个文件的时候,操作系统会为其分配一个文件描述符(先了解,下文讲),当我们获取这个文件描述符之后,就可以对这个文件进行读写等各种操作了

并且这个文件被打开后,在操作系统内核中会为其创建一个结构体 struct file 来进行管理(这和 C 语言的 FILE 结构体不一样),它记录了文件的状态,读写位置等文件信息,它是在内核空间中的,而 C 语言的 struct FILE 是在用户空间中的

并且在 struct file 中存在一个指向缓冲区的指针,可以将数据暂存在缓冲区中,而文件通常会被划分成若干个页(4KB),在打开文件 / 读取文件的时候,操作系统会读取相应的块到该文件的缓冲区中

1.3 文件描述附表

  • Linux 中,进程被描述成 task_struct 进行管理(PCB),而task_struct 中有个指针 struct files_struct* files,该指针负责描述该进程的文件相关数据信息
struct task_struct {
	volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
	void *stack;
	...
	struct files_struct *files;   // 负责描述进程的文件信息数据
	...
}
  • struct files_struct* files 指向的结构体中有一个成员 struct file* fd_array,就是「文件描述符表」(新版本的内核版本可能称为 fdt

在这里插入图片描述

  • 这个文件描述符表,的下标(准确来说是索引)就称为「文件描述符」,而文件描述符表下标对应的对象fd_array[i]就是 struct file*,是指向内核中用来描述被打开文件的结构体
  • 并且在修改相关配置的情况下,一个进程默认可以打开 32 或者 64 个文件,在修改的情况下,可以达到 10w 个,也就是文件描述符表的大小可以达到的大小

注意:

  • 每个进程都会有文件描述符表,并且子进程的创建也会拷贝父进程的文件描述符表,打开相应的文件

综上所述,这里画个图:

在这里插入图片描述
⭐实际上,Linux 在操作文件时,大部分是通过文件描述符表中的下标来进行操作的,而这个下标就是文件描述符 fd,这个很重要,比如 wrtiereadsend 等系统调用接口都是对 fd 进行操作的。

1.4 打开文件时

当进程打开一个文件的时候,在内核中,会创建这个文件对应的 struct file ,然后在文件描述符表中分配一个没有被使用下标 chosenIndex,然后让 fd_array[chosenIndex] 中填入这个 struct file 的地址,再将这个下标 chosenIndex 返回给用户

  • 分配原则:文件描述符表会从头开始遍历,找到一个最小,没被使用的文件描述符并返回。
  • 在 Linux 中,大部分对文件的操作,都是对文件描述符 fd 作操作

在这里插入图片描述

1.5 默认打开的三个文件

Linux 中所有的进程都会默认打开 3 个文件,分别是 stdin(标准输入),stdout(标准输出),stderr(标准错误),它们所占用的文件描述符分别是 0,1,2

一般情况下,标准输入就是键盘,标准输出和标准错误都是和显示器绑定,所以向标准输出和标准错误中输出,都会在显示屏上显示

标准输出一般是接收程序的正常打印结果,标准错误一般是接收程序的错误或者异常结果

这里可以试试,我直接往 1 号和 2 号文件描述符中写入数据:

在这里插入图片描述可以看出,向 1 号和 2 号打印的数据都往显示屏上打印了,

所以我们在程序中,打开文件获取到的文件描述符通常是从 3 开始

在这里插入图片描述

2. 重定向

2.1 瞅瞅

先了解什么是重定向:是一种改变输入源或者输出目标的方式,允许就输入或输出从默认的位置转移到其他位置。还是晦涩的话,这么理解就好了:本来应该写到 xxx 中,现在写到了 yyy 中

举例子:echo 是向显示屏中打印数据:

在这里插入图片描述
这直接打印到了屏幕上对吧

我们现在使用 > ,它在 Linux 命令行中是输出重定向(类似的>> 是追加重定向)
现在我将上面那段输出 重定向 到文件中:

在这里插入图片描述

可以看出本来是打印到显示屏上的,现在写到了 hello.c 文件中,这也就是重定向了

2.2 dup2

首先我们先了解关于重定向的一个接口 dup2

在这里插入图片描述
这个接口要求传入两个文件描述符,这个函数的作用简单来说可以这么理解:

  • fd_array[newfd] = fd_array[oldfd],就是将文件描述符表中,oldfd 对应的内容拷贝给 newfd 对应的位置。也就是会有两个文件描述符指向同一个文件

比如下面这个代码,我打开了一个文件,然后执行 dup2(fd, 1),那么文件描述符表发生了啥 o.0?

int main()
{
    int fd = open("hello.c", O_RDONLY);
    if (fd < 0)     return 0;

    dup2(fd, 1);
    return 0;
}

如下图,

  1. 打开文件的时候,在内核为这个文件创建 struct file 数据结构,然后为其分配文件描述符,并放到 fd_array 中管理,再返回文件描述符
  2. fd_array[1] 中的指针指向这个文件的 struct file

在这里插入图片描述
⭐关键点就是将 fd_array[newfd] 的指针改成成指定的 struct file

然后看看下面代码演示一下:重定向之后,原本写在 1 号文件(也就是显示屏)中的数据现在写到了文件 hello.c 文件中。

在这里插入图片描述其实到这里,重定向的实现原理就七七八八了,我们下面再梳理一下应该就晓得了

2.3 实现原理

  • 当执行 dup2(fd, 1) 的时候,将文件描述符 fd 的内容拷贝给 1 号,这时候 fd1 对应的指针都指向 hello.c
  • 文章开头说过,Linux 中大部分对文件的操作都是对文件描述符的操作
  • ⭐在这个例子中,write / read同样是对文件描述符作操作,通俗点,就是操作系统只会对 fd 下标操作,并不关心fd_array[fd]里面是谁
  • 所以当执行 write(1, str, strlen(str)) 的时候,操作系统就直接往 1 号下标对应的文件进行写入了,它并不关心 1 号下标的文件是不是stdout (强调)
  • 所以最终表现出来的情况就是「本该向显示屏中输出,现在输出到了 hello.c 文件中」

在这里插入图片描述

3. 一切皆文件

众所周知,电脑可以有很多外设,比如键盘,鼠标,声卡,音响,显示屏,网卡,磁盘…,而 Linux 怎么将这些看起来就离谱的硬件也抽象成文件的

这些外设,大都有自己的读操作和写操作,而 Linux 不应该专门为每个硬件设计相应的读写方法,甚至设计相应的数据结构,这样不便于维护和管理,而且很麻烦,如果统一起来就好了

  • 实际上在操作系统和硬件之间,还有一层软件层 —— 驱动,每个硬件通常都有配置一个特定的驱动,驱动可以和硬件交互控制,也可以将操作系统的指令翻译成硬件可以理解的指令 / 命令
  • 所以驱动可以理解成操作系统和硬件交互的桥梁
    它可以为操作系统提供统一的接口(比如读写接口,下文也以读写接口举例子),借此操作系统可以实现对硬件的间接控制,以及完成两者之间的交互
    在这里插入图片描述

还记得 struct file 结构体吗,前面说了这是一个操作系统内核中描述 / 管理文件的结构体,那么要怎么利用这个结构体来将底层硬件结合 / 统一起来?

可以在 struct file 中提供若干个函数指针,比如 ssize_t (*read)()ssize_t (*write)(),然后这些函数指针直接指向驱动层提供的读写接口,指针不必关心自己到底指向了哪个函数,对于 Linux 来说,它只知道只要调用 struct file 中的 write 函数,就一定会执行对应驱动提供的写操作接口,从而以管理文件的方式,实现从底层硬件的控制

在这里插入图片描述

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

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

相关文章

Coinbase:如有必要,不惜在最高法院与SEC“一决胜负”!

6日早间&#xff0c;央视财经频道&#xff08;CCTV-2&#xff09;对“币安及其首席执行官被美证交会&#xff08;SEC&#xff09;起诉”进行了报道。 值得一提的是&#xff0c;央视并不常播报加密货币相关新闻&#xff0c;上一次是关于香港监管框架&#xff0c;赵长鹏&#xff…

< 每日算法:一文带你认识 “ 双指针算法 ” >

每日算法&#xff1a;初识双指针算法 &#x1f449; 1. 双指针概念&#xff1a;&#x1f449; 2. 左右指针> 案例一&#xff1a;二分查找> 案例二&#xff1a;双指针 - 移除元素 &#x1f449; 3. 快慢指针> 案例一&#xff1a; 删除排序数组中的重复项 &#x1f449;…

MySQL8安装详细教程

MySQL8安装详细教程 一、下载二、安装三、配置环境 一、下载 官网下载&#xff1a;点击跳转 进入官网后&#xff0c;如下界面 点击Archives可以选择版本进行下载&#xff0c;如下图根据描述操作即可。 百度云下载链接&#xff1a;点击跳转 或者复制到浏览器打开&#xff1a;链…

【1 微信小程序学习-核心思想与体验】

1 小程序的核心技术 .js文件,负责数据处理,函数定义和实现 .wxml文件,组件结构与数据绑定 .wxss文件,组件样式 .json配置信息补充 MVVM架构实现声明式编程 采用MVVM架构,核心是通过数据绑定实现响应式编程(声明式编程). M:数据处理 V:样式结构 VM:数据绑定和事件监听 vue和小程…

程序员的职场危机,能靠技术化解吗?

很多人认为&#xff0c;程序员一定要干到管理层&#xff0c;才会有继续走下去的希望&#xff0c;而踏实做技术的程序员&#xff0c;只会面临淘汰。 事实真是如此吗&#xff1f; △ 截图来源脉脉&#xff0c;如侵删 我们先不说结论&#xff0c;一起看看网友们的看法&#xff1…

Linux | Job control

Linux | Job control 文章目录 Linux | Job control命令直接将命令丢到后台中“执行”的 &将当前工作丢到后台“暂停”&#xff1a;Ctrl z查看后台工作状态&#xff1a;jobs将后台工作拿到前台处理&#xff1a;fg让工作在后台下的状态变成运行中&#xff1a;bg管理后台工作…

Qt6之vc调用qt生成的带ui的dll

受益于跨平台的特性&#xff0c;Qt生成dll的各种语言调用上体现的淋漓尽致&#xff0c;上篇已经演示了qt生成的无ui的dll及vc如何调用它&#xff0c;本篇将演示vc如何调用qt生成的带ui的dll。 传统观点认为Qt生成的带ui的dll受限于 QApplication 的 exec 方法&#xff0c;这样才…

《精通特征工程》学习笔记(6):非线性特征化与k-均值模型堆叠

1.非线性特征 当数据位于一个薄饼状的线性子空间时&#xff0c;PCA 是非常有用的。但如果数据形成了一个更加复杂的形状&#xff0c;情况又将如何呢&#xff1f; 如果线性子空间是一张平展的纸&#xff0c;那么非线性流形的一个简单例子就是卷起来的纸&#xff0c;它有 个非…

《人人健康》期刊简介及投稿邮箱

《人人健康》期刊简介及投稿邮箱 《人人健康》期刊简介&#xff1a; 主管单位&#xff1a;山西出版传媒集团有限责任公司 主办单位&#xff1a;山西三晋报刊传媒集团有限责任公司 国际刊号ISSN&#xff1a;1004-597X 国内刊号CN&#xff1a;14-1033/R 邮发代号&#xff1…

不甘做小弟,JS时间对象又在搞事情!(上)

关注“大前端私房菜”微信公众号&#xff0c;回复暗号【面试宝典】即可免费领取107页前端面试题。 Date Date 是 js 的一个内置对象&#xff0c;也叫内置构造函数。提供了一堆的方法帮助我们更方便的操作时间 创建时间对象&#xff1a;new Date() 获取时间对象&#xff1a;ne…

NTSC和PAL视频格式的区别

1&#xff0c;历史演变 NTSC早期描述的是525I59.94格式视频&#xff0c;1953年确立标准&#xff0c;美国主导。后来为了方便和PAL制式格式的视频转换&#xff0c;于是将60hz的倍数关系的帧率纳入该系统。 PAL描述的是625I50格式视频&#xff0c;1967年确立标准&#xff0c;欧洲…

完全免费白嫖 GPT-4 的终极方案!

原文链接&#xff1a;https://icloudnative.io/posts/completely-free-to-use-gpt4/ GPT-4 目前是世界上最强的多模态大模型&#xff0c;能力甩 GPT-3.5 好几条街。 大家都希望早日用上 GPT-4&#xff0c;不过目前体验 GPT-4 的渠道非常有限&#xff0c;要么就是开通 ChatGPT …

Java编程笔记31:Record

Java编程笔记31&#xff1a;Record 图源&#xff1a;Fotor懒设计 在日常使用的时候&#xff0c;我们往往需要创建一些“仅用于传输数据的类型”&#xff0c;比如Web编程时候的DTO。 将特殊用途的类型限制为“只读”的一个好处是&#xff0c;这些类型可以安全地在多线程之间共享…

uniapp开发小程序-显示左滑删除效果

一、效果图&#xff1a; 二、代码实现&#xff1a; <template><view class"container"><view class"myorderList"><uni-swipe-action><uni-swipe-action-item class"swipe-action-item" :right-options"option…

【严重】Nacos 集群Raft反序列化漏洞

漏洞描述 Nacos是一个用于动态服务发现和配置以及服务管理的平台。 攻击者可以在Nacos集群处理某些Jraft请求时利用Hessian进行无限制的反序列化&#xff0c;从而造成远程代码执行。 由于Nacos默认监听7848端口处理Raft协议请求&#xff0c;攻击者可能通过向7848端口发送恶意…

[笔记]C++并发编程实战 《四》同步并发操作

文章目录 前言第4章 同步并发操作4.1 等待一个事件或其他条件4.1.1 等待条件达成4.1.2 使用条件变量构建线程安全队列 4.2 使用期望值等待一次性事件4.2.1 后台任务的返回值4.2.2 任务与期望值关联4.2.3 使用(std::)promises4.2.4 将异常存与期望值中4.2.5 多个线程的等待 前言…

【Mysql】InnoDB 中的聚簇索引、二级索引、联合索引

一、聚簇索引 其实之前内容中介绍的 B 树就是聚簇索引。 这种索引不需要我们显示地使用 INDEX 语句去创建&#xff0c;InnoDB 引擎会自动创建。另外&#xff0c;在 InnoDB 引擎中&#xff0c;聚簇索引就是数据的存储方式。 它有 2 个特点&#xff1a; 特点 1 使用记录主键…

【每日挠头算法题(2)】压缩字符串|仅执行一次字符串交换能否使两个字符串相等

文章目录 一、压缩字符串思路 二、仅执行一次字符串交换能否使两个字符串相等思路1&#xff1a;计数法思路2&#xff1a;模拟法 总结 一、压缩字符串 点我直达~ 思路 使用双指针法 大致过程如下&#xff1a; 使用双指针&#xff0c;分别读&#xff08;read&#xff09;&…

mPak的使用文档

mpak介绍 mpak是一种文件格式&#xff0c;同时也是一款虚幻引擎插件&#xff0c;该插件提供了打包、解析和挂载mPak文件的方法&#xff0c;将不同平台的软件包和未编译的资源集成到mPak文件中&#xff0c;该文件具有跨平台兼容性。它支持不同阶段的挂载&#xff0c;例如在编辑…

monaco-editor插件自定义编辑器内容颜色

开始之前先说一下他的自定义内容颜色的api monaco.languages.setMonarchTokensProvider((languageId: string, languageDef: IMonarchLanguage | Thenable<IMonarchLanguage>)) 参数解析&#xff1a;接收两个参数 一个是你要设置的编辑器语言种类&#xff0c;可以是sq…