学习系统编程No.11【重定向的本质】

引言:

北京时间:2023/3/27/7:05,哈哈哈,首先是开心,因为上篇博客热榜目前第15,让我初步掌握了上热榜的小妙招,不单单只是要日更,还有非常多的上榜小技巧,但是首先连续更新的占比还是比较大的,好像连续更新上榜的概率更大,所以让我们开始连续更新吧!今天我们就来学一学真正的基础IO、文件系统和承接上文的部分知识,如缓冲区、重定向等!So,here we go!

在这里插入图片描述

再谈缓冲区

回顾一切皆文件

当操作系统需要访问文件对象时,第一时间就是找到该进程对应的pcb,然后从该pcb中找到指向文件描述符表的指针,通过这个指针找到文件描述符表,进而找打文件描述符表中的各个文件对象的地址,所以在进程看来,它访问的都是一个一个的文件对象而已,根本没有和外设的驱动程序进行交互,因为这个工作已经被文件对象中的读写函数指针给搞定了,并且如果操作系统需要读写数据到相应的外设中,那么此时第一时间就是将数据拷贝到文件对象的文件缓冲区中,然后让文件对象中的相关函数指针去和外设的驱动程序进行交互,进而把数据读写到外设中,所以这就是为什么在Linux操作系统中一切皆文件的原因了,具体如下图所示:
在这里插入图片描述
这种结构或者说这样设计的好处就是:无论底层怎样差异化,我们通过文件对象中的函数指针的方式都可以很好的屏蔽这些差异,让操作系统通过进程,进程通过文件对象把数据准确无误的拷贝到相应的外设中或者是读取外设中的数据。并且这种做法就是传说中的多态,一个面向对象的过程;并且因为我们想用访问操作系统,只能通过进程的方式,所以无论我们用什么方式访问,我们都是用进程的方式去访问操作系统,然后因为进程只能看到文件,所以对于我们来说,我们看到的也就是一切皆文件

系统层面和语言层面相结合

首先,通过上述的知识,我们明白了,操作系统想要访问一个文件,就必须找到该文件对应的进程,找到进程对应的文件描述符表,最终根据地址找到文件对象,如果找不到文件对象,就访问不了相对应的外设,并且任何语言想要访问外设或者文件,必须贯穿体系结构,调用系统调用,经历操作系统,所以我们现在写代码使用的头文件本质都是在调用一个一个的库(C库),通过这些库的封装,去调用系统接口,进而通过操作系统到进程,通过进程到文件描述符表,最后在文件描述符表中找到对应的文件,所以明白,C库本质调用它时,它就会被放在一个可执行文件中,所以C库本质可以理解就是一个进程,用户通过进程就可以去调用操作系统,并且操作系统想要找到对应的文件,又需要根据该进程(此时就是C库),因为只有该进程中有指向文件描述符表的指针,进而操作系统通过该进程中的指针找到文件描述符表,然后找到文件,所以明白最重要的一个道理 , 就是我们的进程中一定是需要有指向文件描述符表的一个指针,并且因为此时C库就是调用操作系统的那个进程,所以明白,C库中一定有指向文件描述符表的指针, 明白这个道理之后,再明白一个道理:

深入FILE*

上篇博客中,我们已经了解了语言层面的文件操作(fopen,fclose,fread等),但是我们会发现,无论使用什么接口,此时都需要使用一个FILE* 的指针来接收该接口的返回值,所以FILE* 到底是什么呢?通过上述对C库的理解,我们知道,C库中一定有一个指向文件描述符的指针,并且明白,C库中的文件操作函数是通过封装系统调用接口(open、close、read等)实现了**,所以我们可以推测FILE是一种数据类型,是一个结构体**,明白 FILE 就是C库里面封装的一个结构体,此时在该结构体中,就存在着各种系统接口的封装和指向文件描述符的指针, 并且在使用的时候,就是通过这个指向文件描述符的指针去找到对应的文件地址,然后把这个地址传给封装的接口(fopen),最后通过这个封装的接口,把地址传给系统调用的接口(open;如下图所示:就是Linux系统中C库中的FILE结构体封装

在这里插入图片描述

所以明白了这两点之后,我们就明白了语言层面的文件操作的具体原理了,如下图,证明我们的语言层面封装的库中存在指向文件描述符表的指针:

在这里插入图片描述

重定向的本质

通过上篇博客中对文件描述符的认识,此时我们明白,当一个进程创建只是,操作系统是默认已经打开了三个文件:标准输入、标准输出和标准错误,并且知道,它们对应的在文件描述符表中的下标是0 1 2 ,并且明白一个道理,就是在进程中,如果该进程对应的代码数据,具有打开文件的操作,此时操作系统就会把在磁盘中对应的文件加载到内存,然后创景一个文件对象(struct file),并且会把该文件对象的地址给给文件描述符表保管(目的提高效率),并且在文件描述符表中存储该地址的时候,是按照一定的规律的,并不像是物理内存一样,放在一个随机的地方,而是按照统一原则,将最小的没有被使用的数组元素(也就是那个下标),分配给该被打开的文件对象的地址 ,如下图右侧所示,此时进行了5次文件的打开,所以在文件描述符表中,就是从0 1 2 之后的下标3 4 5 6 7 开始存放相应的文件对象地址(虽然是同一个文件,但是不影响,考虑的是打开该文件的次数),但是如果此时你像右边图片一样,把标准输入文件给关闭,也就是等于将文件描述符表下标为0中的地址给清空掉,此时操作系统就允许你往该下标中存放文件对象的地址,所以右图的打印就是0 3 4 5 6文件描述符的下标对应的就是文件的返回值

如图深入文件描述符表的理解:
在这里插入图片描述

输出重定向

搞懂了上述现象是为什么,此时我们就深入看看下图的现象,正式了解重定向的本质,可以发现,当我们把标准输入文件给关闭并且打开了一个log.txt文件,通过上述现象明白,因为标准输入被关闭,所以log.txt这个文件对象的地址,此时就是存储在文件描述符表中下标为1的位置,然后最后通过打印发现,如果不把标准输入关闭,那么此时的打印结果,就是向标准输入文件中打印(也就是打印到我们的显示器上),但是如果,我们把标准输入给关闭(就是文件描述符表下标为1),此时可以发现,当我们再一次执行程序的时候,显示器上就不会再打印出我想要的内容,反而当我们查看被打开文件log.txt(也就是此时存储在文件描述符表中下标1处的文件对象地址)此时该文件中的内容是我想要打印的内容,这是为什么呢?所以上述的这一些奇奇怪怪的现象,我们就把它称为输出重定向将本应该在标准输出(显示器)上输出的数据通过重定向的方式在别的文件中输出(log.txt) ,具体如下图所示:

一图搞定输出重定向:
在这里插入图片描述

结论: 我们无论是去调用系统调用接口还是调用库函数,本质上这些接口都不关心它是否是向标准输出文件中打印数据,它们只关心在文件描述符表中下标为1的位置处有没有文件对象的地址给它打印,到底向那个文件对象打印,它根本不在乎。

重定向原理:在上层无法感知的情况下,在操作系统内部,更改进程对应的文件描述符表中的下标中指针指向的地址

输入重定向

明白了上述输出重定向的原理,此时如下图所示,输入重定向也是同理的,本质就是将系统默认打开的标准输入、标准输出和标准错误文件关闭,然后按照文件描述符表的规律,让该下标拥有一个新的文件,此时通过这个文件进行读写步骤
在这里插入图片描述

追加重定向

并且我们通过输出重定向可以明白一个点,就是当我们需要将数据输出到标准输入或者某个下标为1的文件中时,这个文件每次都是会被清理的,导致我们每次写入的数据都是重新开始的,所以此时我们的追加重定向的原理,本质上就是将打来文件的方式给变换一下,从原来的 int fd = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666); 变成 int fd = open(LOG,O_WRONLY | O_CREAT | O_APPEND,0666); 如这两句代码一样,只要把 O_TRUNC(清理)改成O_APPEND(追加),这样我们就从输出重定向,直接就变成了一个追加重定向了,所以输出重定向和追加重定向So,So!

总:无论是输出重定向还是追加重定向,它们都是想文件描述符表中下标为1中写入数据

北京时间:2023/3/27/23:22
在这里插入图片描述

总结:不能熬夜,作息要稍稍健康一些,所以睡觉啦!像什么基础IO和文件系统我直接摆烂,哈哈哈!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【备战蓝桥杯】----01背包问题(动态规划)

🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前…

【数据结构】堆(堆的实现 堆向下调整算法 堆的创建 堆的插入 堆的删除 堆的代码实现 堆的应用)

文章目录堆的实现堆向下调整算法堆的创建堆的插入堆的删除堆的代码实现堆的应用堆的实现 堆是属于操作系统进程地址空间内存区域的划分。 我们下面实现数据结构中的堆。 堆是一个完全二叉树&#xff1a;分为小根堆和大根堆。 小根堆&#xff1a;任何一个节点的值都<孩子的…

YOLOv8原理解析:重新定义实时目标检测的速度和精度

文章目录0.前言1.YOLOv51.1 YOLOv5网络回顾1.2 YOLOv5网络结构图2.YOLOv82.1 YOLOv8概述2.2 YOLOv8整体结构图2.3 YOLOv8yaml 文件与 YOLOv5yaml 文件对比2.3.1 参数部分2.3.2 主干部分2.3.3 Neck部分2.3.4 Head部分2.4 正负样本分配策略2.4.1 静态分配策略和动态分配策略有什么…

【嵌入式烧录/刷写文件】-1.1-详解Motorola S-record(S19/SREC/mot/SX)格式文件

目录 1 什么是Motorola S-record 2 Motorola S-record的格式 2.1 Motorola S-record的结构 2.1.1 “Record type记录类型”的说明 2.1.2 “Record length记录长度”的说明 2.1.3 如何计算“Checksum校验和” 2.2 Record order记录顺序 2.3 Text line terminator文本行终…

【C语言】柔性数组

柔性数组1. 柔性数组介绍2. 柔性数组特点3. 用例3.1 代码一&#xff1a;3.2 代码二&#xff1a;4. 柔性数组优势&#xff1a;1. 柔性数组介绍 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff0c…

#详细介绍!!! 线程池的拒绝策略(经典面试题)

本篇单独讲解线程池的拒绝策略&#xff0c;介绍了当线程池任务满了之后&#xff0c;线程池会以什么样的方式来响应添加进来的任务 目录 一&#xff1a;理解线程池拒绝策略的触发情况代码理解 二&#xff1a;线程池的四种常见的拒绝策略 1.ThreadPoolExecutor.AbortPolicy 2…

【Spring6】| GoF之代理模式(静态代理和动态代理)

目录 一&#xff1a;GoF之代理模式 1. 对代理模式的理解 2. 静态代理 3. 动态代理 3.1 JDK动态代理 3.2 CGLIB动态代理 一&#xff1a;GoF之代理模式 1. 对代理模式的理解 生活场景1&#xff1a;牛村的牛二看上了隔壁村小花&#xff0c;牛二不好意思直接找小花&#xff…

内网渗透之某后渗透利用【网络安全】

0x01 工具介绍 工具原理 Mimikatz 的主要原理是在 Windows 系统中用户登录后系统会将身份凭证存储于lsass.exe进程的内存当中&#xff0c;Mimikatz 通过注入lsass.exe进程读取进程内存&#xff0c;从中获取对应的明文密码。 常见问题 在 Windows Vista 系统之后不再存储 LM…

0203优先级下的调度问题_环_拓扑排序-有向图-数据结构和算法(Java)

1 概述 在和有向图相关的实际应用中&#xff0c;有向环特别的重要。在实际应用中&#xff0c;一般只会重点关注其中的一小部分&#xff0c;或者只想知道它们是否存在。 2 调度问题 一种应用广泛的模型是给定一组任务并安排它们的执行顺序&#xff0c;限制条件是这些任务的执…

机器学习:逻辑回归模型算法原理(附案例实战)

机器学习&#xff1a;逻辑回归模型算法原理 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#…

Github学生包申请秒过经验并使用Copilot

写在前面 前提是在校学生&#xff0c;且有学校邮箱&#xff0c;当然你也得有Github账户前往学信网下载 教育部学籍在线验证报告将报告转换成英文版本&#xff0c;我用的是手机夸克自带的拍照翻译功能 具体流程 设置Github个人信息 来到 https://github.com/settings/profil…

如何用Postman做接口自动化测试?没有比这个更详细的了

目录 前言 什么是自动化测试 自动化测试有哪些分类 为什么需要自动化测试 Postman自动化测试演示 1.新建集合 2.新建接口 3.填写自动化测试脚本 4.录入所有接口 5.执行自动化测试 前言 什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 …

腾讯Coding平台学习笔记二:自定义团队插件的使用方法

目录一、前言二、系统环境三、工作目标四、流水线设置五、开发工具5.1 教程地址5.2 开发工具程序结构5.3 qciplugin.yml文件5.4 main.py文件六、插件的安装6.1 打包成zip6.2 上传zip包6.3 构建新插件6.4 质量门禁7、流水线设置7.1 添加质量管理阶段节点7.2 添加其它动作八、流水…

cookie和session的原理以及在Servlet中的应用

文章目录简介cookiecookie的实质及实现原理cookie在Servlet的应用sessionsession的实质及实现原理session在Servlet中的应用HttpServletRequest&#xff0c;Session&#xff0c;ServletContext简介 cookie保存在客户端&#xff0c;session保存在服务器端。二者均用于描述会话的…

【第十一届“泰迪杯”数据挖掘挑战赛】B题产品订单的数据分析与需求预测“解题思路“”以及“代码分享”

【第十一届泰迪杯B题产品订单的数据分析与需求预测产品订单的数据分析与需求预测 】第一大问代码分享&#xff08;后续更新LSTMinformer多元预测多变量模型&#xff09; PS: 代码全写有注释&#xff0c;通俗易懂&#xff0c;包看懂&#xff01;&#xff01;&#xff01;&…

RK3568平台开发系列讲解(驱动基础篇)IO 模型的分类

🚀返回专栏总目录 文章目录 一、阻塞 IO二、非阻塞 IO三、IO 多路复用四、信号驱动五、异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将针对IO模型进行分类。 假设有这样一个场景,从磁盘中循环读取 100M 的数据并处理,磁盘读取 100M 需要花费 20 秒的…

Transformer在计算机视觉中的应用-VIT、TNT模型

上期介绍了Transformer的结构、特点和作用等方面的知识&#xff0c;回头看下来这一模型并不难&#xff0c;依旧是传统机器翻译模型中常见的seq2seq网络&#xff0c;里面加入了注意力机制&#xff0c;QKV矩阵的运算使得计算并行。 当然&#xff0c;最大的重点不是矩阵运算&…

【数据结构】树的概念

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

网络基础认识

目录 一、计算机网络背景 1.1 网络发展 1.2 "协议"由来 二、网络协议初识 2.1 协议分层 2.2 OSI七层模型 2.3 TCP/IP五层模型 三、网络协议栈 四、数据包封装与分用 五、网络传输基本流程 5.1 同局域网的两台主机通信 5.2 跨网络的两台主机通信 六、网络…

MySQL高级第六篇:数据库性能分析与优化

MySQL高级第六篇&#xff1a;数据库性能分析与优化一、数据库服务器优化步骤概述二、慢查询日志&#xff1a;记录执行慢的SQL1. 开启慢查询日志2. 设置long_query_time3. 查看慢查询数与慢查询SQL三、分析查询语句&#xff1a;EXPLAIN1. 概述2.EXPLAIN各列的含义一、数据库服务…