重定向原理和缓冲区

文章目录

  • 重定向
  • 缓冲区

正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默,忍不住分享一下给大家。 点击跳转到网站。

重定向

内核中为了管理被打开的文件,一定会存在描述一个文件的file结构体,这个结构体中大概有什么呢?
我们知道文件=文件内容 + 文件属性,所以file结构体中一定会存在打开文件的各种属性,其次它也一定存在自己的读写方法,也就是方法集,文件的内容是存在在磁盘中的,所以file中又一个属于内核级别的文件缓冲区,所以当我们读写文件的时候,是需要把文件的内容拷贝到文件缓冲区中的,然后如果读文件就把缓冲区中的内容拷贝到我们自己的定义的缓冲区中,如果写或者修改的话就把内容拷贝到内核缓冲区中,然后刷新到磁盘,所以我们在应用层进行的数据读写的本质就是将内核缓冲区的内容进行来回拷贝。不管是读文件还是写文件都需要先把内容拷贝到文件缓冲区。

fd的分配规则
进程是默认打开了0,1,2文件描述符的,我们在打开一个文件fd就是3,如果我们关闭了1,然后在进行打开文件,那么新打开的文件fd就是1,所以文件描述符的分配规则是遍历文件fd表,寻找最小的没有被使用的位置,然后分配给打开的文件。

重定向原理

重定向的就是把本来应该打印到显示器的内容打印了文件中,而往显示器打印本质就是想显示器文件打印,因为C语言中的标准输入输出本质就是封装了fd0和1,所以我们利用文件描述符的分配规则就可以自己实现一个简单的重定向功能。
如果我们要实现一个输出重定向的话,我们只需要把fd1关了,然后再打开一个文件,然后我们往显示器中打印内容,就会往fd1中打印,但是现在文件1指向的是我们自己新打开的文件。输入同理。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    close(1);
    int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC , 0666);
    if(fd < 0) return -1;

    printf("hello printf\n");
    fflush(stdout);
    close(fd);
    return 0;
}

在这里插入图片描述
所以通过这种方式我们就可以自己实现一个输出重定向。但是我们每次都要自己关闭1号文件描述符,这样太麻烦了,那么如果存在一种可以把我们打开的文件的fd内容覆盖1号下标的内容就可以实现这个技术,所以重定向的本质就是修改文件描述符表。对于用户来说,fd是不变的,但是fd指向的内容改变了。系统中有一个函数dup2就可以实现这个功能。
在这里插入图片描述
dup2就可以让oldfd覆盖到newfd。对于被覆盖的文件,OS会自动帮你关闭的,所以我们通过这种方式也可以实现重定向功能。
以输入重定向为例:
dup2(fd,0)就可以实现下图的效果。
在这里插入图片描述
所以重定向的本质就修改文件描述符指向的内容,命令行级别的只需要对字符串进行特定的解析,然后调用dup2函数就可以实现重定向功能。程序替换时不会影响重定向的,因为程序替换只会替换代码和数据,对于进程的PCB是不影响的,所以对于PCB指向的文件fd

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC , 0666);

    if(fd < 0) return -1;
    //使用dup2
    dup2(fd,1);

    printf("hello hello\n");
    close(fd);
    return 0;
}

在这里插入图片描述
如果是对于追加和输入重定向的话,我们只需要控制一些打开文件时,打开的方式就可以实现,和输出同理。

我们知道标准输入和标准输出是我们平时使用必不可少的东西,所以系统会帮我们自动打开,这都没毛病,但是标准错误是什么东西??

#include <stdio.h>
int main()
{
    printf("i am printf\n");
    perror("i am perror ");
    return 0;
}

如果我们直接运行:
在这里插入图片描述
如果我们重定向一下:
在这里插入图片描述
可以通过这种方式把标准输出和标准错误打印的东西分开打印,perror和cerr都是向标准错误中打印,我们可以通过重定向把标准输出和标准错误打印的东西分别打印到不同的文件方便调试。

打印到同一个文件
在这里插入图片描述
打印到不同文件:
在这里插入图片描述

缓冲区

什么是缓冲区?
缓冲区的本质就是一快内存,用来存放数据的。

为什么要有缓冲区?
缓冲区的主要作用就是提高效率,谁使用缓冲区就提供谁的效率,因为有缓冲区的存在,我们在写一些东西的时候一定会涉及I/O操作,就一定会访问硬件,所以通过缓冲区累计一部分数据后再进行发送会远远比每次都进行I/O的效率要高很多。可以提高发送的效率。

缓冲区能够缓存一定的数据,就一定会存在自己的刷新策略:

  1. 全缓冲(缓冲区满了,在进行刷新)
  2. 行缓冲(行刷新)
  3. 无缓冲(立即刷新)

这三种是一般的策略,用户也可以通过fflush这样的函数来进行强制的刷新,并且在进程结束的时候,一般都要进行缓冲区的刷新的。一般对于显示器文件来说是行刷新,对于普通的磁盘文件是全刷新的。

我们可以通过一个样例来证明一下这个缓冲区的存在:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main()
{
    printf("hello printf\n");
    fprintf(stdout, "hello fprintf\n");
    fputs("hello fputs\n", stdout);

    char buffer[1024] = "hello write\n";
    write(1,buffer,strlen(buffer));
    pid_t id = fork();
    return 0;
}

这个代码很简单就不解释了,我们先直接运行一下,然后在重定向一下,看结果:

在这里插入图片描述
那么为什么会出现这个现象呢?

  1. 当我们直接运行的时候我们调用的所有接口都是向显示器文件打印,而显示器文件的刷新方式是行刷新,而我们所有的打印后面都有‘\n’,所以在fork()之前,我们的数据都已经被刷新了,包括write系统调用。
  2. 当我们重定向的时候,本质已经是向磁盘文件中打印了,不是向显示器文件打印了,所以刷新方式已经变成了全缓冲。
  3. 全缓冲就意味着缓冲区很大,当我们fork的时候,我们实际写入的数据很少,不足以把缓冲区打满,所以当fork的时候数据仍然在缓冲区中。
  4. 我们可以看到,重定向之后,只有C语言的接口打印了两次,而write系统调用只打印了一次,所以我们目前说的缓冲区是C语言提供的,和操作系统没有任何关系。也侧面证明了exit和_exit的区别,一个C语言提供的,程序退出刷新缓冲区,一个系统调用,不刷新缓冲区,所以这个缓冲区一定是C语言提供的。
  5. C/C++提供的缓冲区,里面保存的一定是我们用户的数据,只要我们不刷新,这个数据就属于我们用户,但是如果我们把缓冲区的数据写入了OS中,那么这部分数据就不属于我们了,而是属于OS。
  6. 当进程退出时一般都要刷新缓冲区,即使没有达到刷新的条件。而刷新的本质即使清空缓冲区,清空也是写入。所以当我们重定向向文件中打印的时候,系统调用会先先打,而C语言提供的接口打印的东西都还在C语言提供的缓冲区中,当我们fork创建子进程后,子进程会继承父进程的大部分数据,当子进程或者父进程退出时,退出的一方要刷新缓冲区,也就是写入,由于父子之间具有独立性,就要发生写时拷贝,这时,就出现了上面C语言接口打印两次的情况。

我们之前说过文件也有自己的文件缓冲区,也就是内核缓冲区,所以C语言的缓冲区和内核缓冲区的关系就是我们平时先把数据拷贝到C语言的缓冲区,根据刷新的机制在刷新到文件缓冲区,然后OS根据自己的安排定时刷新到磁盘。所以文件读写的本质就是来回拷贝。
在这里插入图片描述
从用户缓冲区拷贝到文件缓冲区的过程就是我们平时说的刷新。
我们在使用C语言的I/O接口是,都会接触FILE结构体,就连默认打开的3个流都是FILE指针类型。
在这里插入图片描述
因此C语言提供的缓冲区就是在FILE结构体中。所以FILE中不仅封装了fd文件描述符,还封装了缓冲区。

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

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

相关文章

蓝牙技术在智能硬件中应用火热,你的蓝牙适配测试如何解决?

蓝牙技术在物联网中的应用非常广泛&#xff0c;可以为人们的生活和工作带来更多的便利和智能化体验&#xff0c;主要五大核心应用场景&#xff0c;具体如下&#xff1a; 1、智能家居 通过蓝牙连接智能家居设备&#xff0c;如智能灯泡、智能插座、智能恒温器等&#xff0c;可以…

9【原型模式】复制一个已存在的对象来创建新的对象

你好&#xff0c;我是程序员雪球。 今天我们来学习23种设计模式之原型模式&#xff0c;在平时开发过程中比较少见。我带你了解什么是原型模式&#xff0c;使用场景有哪些&#xff1f;有什么注意事项&#xff1f;深拷贝与浅拷贝的区别&#xff0c;最后用代码实现一个简单的示例…

全球半导体排行:台积电登顶,中芯国际第24位

最新发布的《麦克莱恩报告》4月更新揭示了2023年全球前50大半导体供应商的最终排名情况&#xff0c;其中前25强名单尤为引人注目。台积电&#xff08;TSMC&#xff09;凭借强劲的市场表现和业务增长&#xff0c;成功超越其他竞争对手&#xff0c;跃居全球半导体供应商首位。与此…

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo

C# danbooru Stable Diffusion 提示词反推 OpenVINO Demo 目录 说明 效果 模型信息 项目 代码 下载 说明 模型下载地址&#xff1a;https://huggingface.co/deepghs/ml-danbooru-onnx 效果 模型信息 OVVersion { BuildNumber 2023.1.0-12185-9e6b00e51cd-releases/20…

干货!微信小程序通过NodeJs连接MySQL数据库

在前后端数据库架构的思维中&#xff0c;微信小程序的生态地位是充当前端&#xff0c;后端和数据库还需开发者另外准备。微信开放社区提供强悍的云函数、云数据库、CMS内容管理&#xff0c;无疑为开发小程序的功能提供了不少便捷。 当我们在开发PC端的系统时&#xff0c;常见的…

新闻媒体行业邮件推广:精准推送,创造价值

在当今信息爆炸的时代&#xff0c;新闻行业如何在竞争激烈的市场中脱颖而出&#xff0c;吸引读者的目光&#xff0c;成为了每个新闻机构都需要认真思考的问题。许可式邮件营销成为了一种强大的工具&#xff0c;不仅能够向订阅者发送新闻期刊&#xff0c;还能够向广告商发送宣传…

【Spring进阶系列丨第十篇】基于注解的面向切面编程(AOP)详解

文章目录 一、基于注解的AOP1、配置Spring环境2、在beans.xml文件中定义AOP约束3、定义记录日志的类【切面】4、定义Bean5、在主配置文件中配置扫描的包6、在主配置文件中去开启AOP的注解支持7、测试8、优化改进9、总结 一、基于注解的AOP 1、配置Spring环境 <dependencie…

雨伞-浅色脚本

渲染参考&#xff1a;明亮/干净/高级 静帧参考 解说 镜头时长 效果参考 中景画面展示3把竖着的浅色的伞 1s / 特写展示伞把手 1s 中景展示雨伞全貌 2s 微观镜头 缝线动画 3s 镜头旋转至伞面微观材质镜头&#xff0c;展现其多层结构 10s 微观镜头 水珠滑动在伞…

不说成为Linux高级工程师,但成为合格的软件开发人员还是够了,一文深入浅出的精炼总结Linux核心知识点,掌握Linux的使用与高阶技巧

不说成为Linux高级工程师&#xff0c;但成为合格的软件开发人员还是够了&#xff0c;一文深入浅出的精炼总结Linux核心知识点&#xff0c;掌握Linux的使用与高阶技巧。 Linux 的学习对于一个程序员的重要性是不言而喻的。前端开发相比后端开发&#xff0c;接触 Linux 机会相对…

1.SCI各模块

1.学会“抄” 写论文&#xff0c;一定要学会“抄”&#xff01;这样才能事半功倍&#xff0c;尤其是对于初次写作的新手&#xff0c;否则写作过程一定会让你痛不欲生&#xff0c;而且写出来的东西就是一坨shi&#xff0c;不仅折磨自己&#xff0c;也折磨导师。 写论文与建大楼…

Ubuntu 20.04.06 PCL C++学习记录(二十五)

[TOC]PCL中点云分割模块的学习 学习背景 参考书籍&#xff1a;《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,&#xff0c;PCL版本为1.10.0&#xff0c;CMake版本为3.16&#xff0c;可用点云下载地址 学习内容 使用渐进形态滤波器分割识别地面回波&#xff0c;即执…

JookDB下载安装使用

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

离岸人民币与人民币国际化

参考 什么是离岸人民币&#xff1f;它有什么用&#xff1f; - 知乎 “人民币就是人民币&#xff0c;为什么要在它前面加上离岸二字&#xff1f;” “既然有离岸人民币&#xff0c;是否有在岸人民币&#xff1f;” 今天我们就简单了解一下什么是离岸人民币。 离岸/在岸人民币…

久吾高科技股份有限将莅临2024第13届生物发酵展

参展企业介绍 江苏久吾高科技股份有限公司成立于1997年&#xff0c;是一家专注从事新材料研发与整体解决方案的高科技企业。2017年3月在深交所A股创业板上市。公司是首批认定的guojiaji高新技术企业、国家专精特新“小巨人”企业、国家制造业单项、中国膜行业陶瓷膜领域龙头企…

Xinstall一站式App推广解决方案,让营销更高效

在移动互联网时代&#xff0c;App的推广与运营成为了开发者们面临的一大挑战。如何快速有效地推广App&#xff0c;提高安装量&#xff0c;增加用户活跃度&#xff0c;是每一个开发者都迫切需要解决的问题。而Xinstall&#xff0c;作为一家专业的一站式App全渠道统计服务商&…

ESP8266闪存文件系统(SPIFFS)

开发环境&#xff1a; 1、安装ESP8266的开发环境&#xff0c;如Arduino IDE。 2、下载并安装ESP8266的相关开发库和工具。 我们使用的是Arduino IDE。 基本介绍&#xff1a; 每一个ESP8266都配有一个闪存&#xff0c;这个闪存很像是一个小硬盘&#xff0c;我们上传的文件就被…

linux限权

shell命令以及运行原理 什么是shell命令&#xff1a; 将使用者的命令翻译给核心&#xff08;kernel&#xff09;处理。同时&#xff0c;将核心的处理结果翻译给使用者。 shell就相当于操作系统外的一层外壳 其实就是登录linux时的一个可执行程序&#xff08;进程&#xff09…

Python实现BOA蝴蝶优化算法优化随机森林回归模型(RandomForestRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 蝴蝶优化算法(butterfly optimization algorithm, BOA)是Arora 等人于2019年提出的一种元启发式智能算…

图像基础—图像分类

图像通常分为二值图像、灰度图像和彩色图像 图 1-3 二值图像、灰度图像和彩色图像 &#xff08;1&#xff09;二值图像 二值图像又称为黑白图像&#xff0c;图像中任何一个点非黑即白&#xff0c;要么为白色&#xff08;像素 为 255&#xff09;&#xff0c;要么为黑色&#x…

vue简单使用二(循环)

目录 属性绑定 if判断&#xff1a; for循环&#xff1a; 属性绑定 代码的形式来说明 三元表达式的写法&#xff1a; if判断&#xff1a; for循环&#xff1a; 完整代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"…