【Linux】开始了解重定向

在这里插入图片描述
送给大家一句话:

人真正的名字是:欲望。所以你得知道,消灭恐惧最有效的办法,就是消灭欲望。 – 史铁生 《我与地坛》

开始了解重定向

  • 1 前言
  • 2 重定向与缓冲区
    • 2.1 文件描述符分配规则
    • 2.2 重定向的现象
    • 2.3 重定向的理解
    • 2.4 缓冲区的理解
  • 3 进程与重定向
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 前言

上一篇文章我们复习了C文件IO相关操作,了解了linux下的文件系统调用(open write read ),认识了文件描述符fd值,今天我们来学习重定向和缓冲区,这个缓冲区之前遇到过很多次,比如进度条项目的刷新缓冲区操作。然后我们可以来尝试封装一下系统调用,模拟C语言的文件库。

2 重定向与缓冲区

2.1 文件描述符分配规则

接下来我们来了解重定向!
首先我们来看fd文件描述符的分配规则,我们写一段代码来看:

    1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 #include<stdlib.h>8 9 const char* filename = "log.txt";10 11 12 int main()13 {14 	15   int fd = open("myfile", O_RDONLY);16   if(fd < 0){17   perror("open");18     return 1;19   }20   printf("fd: %d\n", fd);21   close(fd);22   return 0;    23   }

我们运行来看:
在这里插入图片描述
这和我们的预期是一样的,我们文件操作那篇文章讲解了fd 的 0 1 2 分别代表了标准输入,标准输出,标准错误。那么在创建的文件描述符很自然的就使用了3! 那么加入我们关闭012中的文件呢,那么新打开的文件描述符会是3吗???

    1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 #include<stdlib.h>8 9 const char* filename = "log.txt";10 11 12 int main()13 {14 	close(0); 15   int fd = open("myfile", O_RDONLY);16   if(fd < 0){17   perror("open");18     return 1;19   }20   printf("fd: %d\n", fd);21   close(fd);22   return 0;    23 }

来看:
在这里插入图片描述
我们新创建的文件的文件描述符就成了 0 !
再来试试:

  • 关闭 2 close(2) -->新创建的文件的文件描述符就成了 2
  • 关闭 1 close(1) -->就什么也打印不出来(标准输出被关闭自然打印不出来)
  • 关闭 0 2 close(2)close(0) --> 新创建的文件的文件描述符就成了 0

这样我们大致可以总结出来一个结论:
文件描述符的分配规则:进程会查自己的文件描述符表,分配最小的并且没有被使用过的 fd

2.2 重定向的现象

刚才我们看到了文件描述符的分配规则,也发现关闭1 (标准输出)就我们打印出来,我们再来探究一下:如果我们关闭了 标准输出,并打开了一个文件,那么该文件就成为了1 ,来看看会发生什么现象:

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 #include<stdlib.h>8 9 const char* filename = "log.txt";10 11 12 int main()13 {14 15   close(1);16 17   int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC , 0666);18   if(fd < 0){19   perror("open");20     return 1;21   }22   printf("fd: %d\n", fd);23   fprintf(stdout,"fprintf fd :%d\n",fd);24 25   fflush(stdout);    26   close(fd);27   return 0 ;

来看效果:
在这里插入图片描述
我们发现并没有在显示器打印出来,而是在新文件log.txt中打印出来了!!!

  1. 因为我们关闭了1号文件 (标准输出
  2. 然后又打开了一个文件,那么1号下标就成了该新文件的文件描述符。
  3. 又因为stdout是对系统的封装,里面封装了 1 号文件
  4. 那么stdout 的指向没有发生改变(还是1 号文件),所以自然就打印到了log.txt中去了!.

这种技术就叫做 重定向,也就是把本应该打印到显示器的内容打印到了一个其他文件中。
其本质就是在内核中改变文件描述符表特定下标的内容,和上层无关!
在这里插入图片描述

可是如果不加入fflush 呢???结果是log.txt文件里也什么都没有?!这就涉及缓冲区的内容了。
首先 一个文件都有一个方法表和内核文件缓冲区。同样在C语言中 (stdin stdout stderr都是struct FILE* 的指针,)文件结构体里面一定封装了fd描述符,而且也封装了语言级的缓冲区。以往的 printf fprintf都是先讲内容写到语言级的缓冲区里在写到文件内核缓冲区了,所以fflush作为一个系统调用,就是刷新文件内核缓冲区,使其输出到文件中!!!
而为什么不加入fflush 呢结果是log.txt文件里也什么都没有呢??? 就是因为内容写入到文件内核缓冲区里还没有刷新就被close关闭了,所以还没刷新就文件被关闭了,还怎么打印到文件中。而且我们不写fflush 不写close 就可以成功打印到文件中!!!

2.3 重定向的理解

完成重定向的操作肯定不是像我们上面做的那样简单粗暴(又要删除,又要创建新文件),我们有一个系统调用dup2

NAMEdup, dup2, dup3 - duplicate a file descriptorSYNOPSIS#include <unistd.h>int dup(int oldfd);int dup2(int oldfd, int newfd);#define _GNU_SOURCE             /* See feature_test_macros(7) */#include <fcntl.h>              /* Obtain O_* constant definitions */#include <unistd.h>int dup3(int oldfd, int newfd, int flags);

每次我们使用dup2 就可以实现重定向 ,来看其功能描述。
dup2() makes newfd be the copy of oldfd, closing newfd first if necessary
通过描述可以知道:

  1. 首先文件描述符的拷贝不是对数字的拷贝,而是下标所对应内容(文件结构体指针)的拷贝
  2. 然后是实现了将oldfd的内容拷贝到newfd(多个下标指向一个文件),dup2( fd , 1 )就是将fd指向的文件拷贝到1 (标准输出)里。

这样通过dup2既可以完成重定向:

    1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 #include<stdlib.h>8 9 const char* filename = "log.txt";10 11 12 int main()13 {14 15   int fd = open(filename , O_CREAT | O_WRONLY | O_TRUNC);16 17   dup2(fd,1);18 19   printf("Hello world!\n");20   fprintf(stdout,"Hello world!\n");                                              21   close(fd);22   return 0;23 }                                          

来看效果:
在这里插入图片描述
这样也实现了重定向的功能!!!比简单粗暴的关闭stdout 再打开新文件好多了!!!
我们也可以将O_TRUNC 换成O_APPEND,这样每次都是追加内容,所以我们的命令也有了对应:

  • > 相当于 O_TRUNC 覆盖
  • >> 相当于 O_APPEND 追加

就这么简单!!!

2.4 缓冲区的理解

缓冲区分为:用户级缓冲区 和 内核缓冲区。缓冲区的作用是:解耦和提高使用者效率

类比生活中,缓冲区就是类似一个超市,我们不需要去工厂进行采购,这样十分麻烦,而直接去超市就解决了问题。也可以比作顺丰快递,我们想要寄东西,只需要交给快递站就可以,我们不需要考虑快递怎么到达目的地!
所以我们操作系统与语言层中,我们的printf 和 fprintf就不需要考虑我们如何将内容写入到文件中,这不是他们需要关心的事情!!!

那为什么会拷贝两次呢???为什么会有两个缓冲区, **因为系统调用是有成本的!**操作系统可能正在执行其他任务,所以为了注重用户体验,就需要缓冲区(也就提高printf fprintf 的效率,因为我们实际上还没有将内容打印到文件,只是打印到了缓冲区,可能调用10次pringtf ,但是只需要刷新一次,是不是刷新IO的效率就高了)

  1. 缓冲区可以理解为一段内存空间
  2. 缓冲区是为了给上层通过良好的IO体验(语言 --> 操作系统 --> 磁盘)
  3. 缓冲区的刷新策略是什么呢?
    • 立即刷新 语言层:fflush() , 系统调用:fysnc(int fd) 相当于无缓冲
    • 行刷新 :显示器(配合人的阅读习惯)
    • 全缓冲,缓冲区写满才刷新:普通文件
    • 特殊情况 :进程退出会自动刷新缓冲区

截图内核的刷新策略我们不关心,就针对用户层面来研究。

3 进程与重定向

我们再来与先前的进程控制结合一下,来看:

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<sys/stat.h>4 #include<fcntl.h>5 #include<unistd.h>6 #include<string.h>7 #include<stdlib.h>8 9 const char* filename = "log.txt";10 11 12 int main()13 {14 15   int fd = open(filename , O_CREAT | O_WRONLY | O_TRUNC);16 17   18 19   printf("Hello printf!\n");20   fprintf(stdout,"Hello fprintf!\n");21 22   const char *msg = "hello write!\n";23   write(1,msg,strlen(msg));                                                                                                                                                   24                                                                                                                                            25   fork();      26   close(fd);27	  return 0;28 }

我们运行一下来看效果:
在这里插入图片描述

啊???这是什么现象???

  1. 显示器与文件的打印顺序不一样
  2. 打印次数不一样?!
  • 现象 1: 是因为显示器采用行刷新所以每次换行就会打印出来,普通文件采用全缓冲,最后才会打印出来,打印顺序类似入栈出栈。
  • 现象 2 : 按理说我们fork()之后,创建了子进程,子进程会继承父进程的代码与数据。那么为什么显示器只打印了一遍呢???因为显示器采用行刷新,fork的时候,语言缓冲区和内核缓冲区里没有内容,所以子进程不会打印出来。而向文件打印时,fork之前语言缓冲区有内容(printf fprintf ),内核缓冲区有内容(write)。fork后 ,子进程会拷贝一份数据也就语言层的缓冲区被打印了两次,内核缓冲区不会拷贝给子进程(不是用户级,所有用户共享)

缓冲区就在struct file 内部!每个文件都有自己的缓冲区

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

5.6 mybatis之RowBounds分页用法

文章目录 mybatis 中&#xff0c;使用 RowBounds 进行分页&#xff0c;非常方便&#xff0c;不需要在 sql 语句中写 limit&#xff0c;即可完成分页功能。但是由于它是在 sql 查询出所有结果的基础上截取数据的&#xff0c;所以在数据量大的sql中并不适用&#xff0c;它更适合在…

【Python】OPC UA 服务器扫描工具

引言 OPC UA&#xff08;开放平台通信统一架构&#xff09;是一种跨平台的、开放的数据交换标准&#xff0c;广泛用于工业自动化领域。在工业4.0的大背景下&#xff0c;OPC UA服务器在网络中的部署日益增多&#xff0c;如何快速有效地发现这些服务器成为了一个实际需求。本文将…

UI自动化测试重点思考(下)--装饰器/生成器/夹具的使用/描述符的作用/ddt驱动/多线程

UI自动化测试重点思考--装饰器 装饰器装饰器定义装饰器代码示例装饰器的执行如何将装饰器融合到pytest框架里面 生成器创建生成器生成器的定义如何将生成器融合到pytest框架里面 fixture&#xff08;夹具&#xff09;使用pytest fixture 中 scope 参数的详细解释 描述符的总结描…

【Sentinel的限流使用】⭐️SpringBoot整合Sentinel实现Api的限流

目录 前言 一、Sentinel下载 二、SpringBoot 整合 Sentinel 三、流控规则 章末 前言 小伙伴们大家好&#xff0c;上次使用OpenFeign时用到了 Hystrix实现熔断和限流的功能&#xff0c;但是发现该工具已经停止维护了&#xff0c;于是想到了Spring Cloud Alibaba开发的Sentin…

高创新 | Matlab实现OOA-CNN-GRU-Attention鱼鹰算法优化卷积门控循环单元注意力机制多变量回归预测

高创新 | Matlab实现OOA-CNN-GRU-Attention鱼鹰算法优化卷积门控循环单元注意力机制多变量回归预测 目录 高创新 | Matlab实现OOA-CNN-GRU-Attention鱼鹰算法优化卷积门控循环单元注意力机制多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现OOA…

如何在CentOS7.x上生成自签名SSL证书

在配置HTTPS连接时&#xff0c;SSL证书是确保数据传输安全性的关键组件。自签名证书是一种不通过证书颁发机构&#xff08;CA&#xff09;签发的证书&#xff0c;适用于测试和内部使用。以下是在CentOS 7.x系统上生成自签名证书的详细步骤。 1. 安装OpenSSL OpenSSL是一个强大…

【嵌入式学习】ARM day04.11

一、思维导图 二、练习 实现三个灯闪烁 汇编代码 .text .global _start _start: 使能GPIOE和F时钟LDR r0,0x50000A28LDR r1,[R0]ORR R1,R1,#(0X3<<4)STR R1,[R0]配置GPIOE和F的MODER寄存器LDR r0,0x50006000 GPIOELDR R1,0X50007000 G…

顶顶通呼叫中心中间件-回铃音补偿(mod_cti基于FreeSWITCH)

顶顶通呼叫中心中间件-回铃音补偿(mod_cti基于FreeSWITCH) 回铃音的用处 回铃音&#xff1a; 当别人打电话给你时&#xff0c;你的电话响铃了&#xff0c;而他听到的声音叫做回铃音。回铃音是被叫方向主叫方传送&#xff0c;也是彩铃功能的基础。我们平时打电话听到的“嘟 嘟…

【C++进阶】C++异常详解

C异常 一&#xff0c;传统处理错误方式二&#xff0c;C处理的方式三&#xff0c;异常的概念四&#xff0c;异常的使用4.1 异常和捕获的匹配原则4.2 函数调用链中异常栈展开匹配原则4.3 异常的重新抛出&#xff08;异常安全问题&#xff09;4.4 RAII思想在异常中的作用 五&#…

2024 Mathorcup高校数学建模挑战赛(B题)| 甲骨文识别 | 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;以CNN卷积神经网络&#xff0c;计算机视觉等强大工具&#xff0c;构建了解决复杂问题的独特方案。深度学习, 混沌模型的妙用&#xff0c;为降低非法野生动物贸易提供新视角。通过综合分析&#xff0c;描…

IP广播对讲系统停车场解决方案

IP广播对讲系统停车场解决方案 一、需求分析 随着国民经济和社会的发展&#xff0c; 选择坐车出行的民众越来越多。在保护交通安全的同时&#xff0c;也给停车场服务部门提出了更高的要求。人们对停车场系统提出了更高的要求与挑战&#xff0c; 需要停车场系统提高工作效率与服…

01-Git 之快速入门操作本地仓库

https://learngitbranching.js.org/?localezh_CN在线练习git 1. Git 安装好Git以后, 先检查是否已经绑定了用户名和邮箱 git config --list1.1 为什么要使用版本控制&#xff1f; 从个人角度&#xff1a; 在做项目时&#xff0c;如果一点点去改代码会很乱&#xff0c;不利…

OpenCV4.9更多形态转换

返回&#xff1a;OpenCV系列文章目录&#xff08;持续更新中......&#xff09; 上一篇:OpenCV4.9处理平滑图像 下一篇:OpenCV4.9更多形态转换 基于这两者&#xff0c;我们可以对图像进行更复杂的转换。在这里&#xff0c;我们简要讨论 OpenCV 提供的 5 个操作&#xff1a; …

FreeBuf 全球网络安全产业投融资观察(3月)

综述 据不完全统计&#xff0c;2024年3月&#xff0c;全球网络安全市场共发生投融资事件53起&#xff0c;其中国内4起&#xff0c;国外49起。 3月全球络安全产业投融资统计表&#xff08;数据来源&#xff1a;航行资本、36氪&#xff09; 整体而言&#xff0c;国内4起投融资事…

AI写作软件哪个好?这4款好评如潮

在信息时代&#xff0c;AI技术的发展的日新月异&#xff0c;AI写作软件也因此诞生。特别是人们对于高效、便捷的写作工具需求日益增长&#xff0c;AI写作软件作为一种新兴的工具&#xff0c;在帮助人们提升写作效率、拓展创作思路方面发挥着越来越重要的作用。这些AI写作软件为…

C语言 函数——代码风格

目录 基本的代码规范 程序版式 对齐&#xff08;Alignment&#xff09;与缩进&#xff08;indent&#xff09; 变量的对齐规则 空行——分隔程序段落的作用 代码行内的空格——增强单行清晰度 代码行 长行拆分 标识符命名规则 标识符命名的共性规则 windows应用程序…

PostgreSQL入门到实战-第十八弹

PostgreSQL入门到实战 PostgreSQL中表连接操作(二)官网地址PostgreSQL概述PostgreSQL中表别名命令理论PostgreSQL中表别名命令实战更新计划 PostgreSQL中表连接操作(二) 了解PostgreSQL表别名及其实际应用程序。 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容…

19c数据库/dev/shm/过小导致pga内存不够

pga_aggregate_limit已经设置了120G&#xff0c;alert还是报内存不够 查询select * from v$pgastat&#xff0c;发现MGA占了80G内存 查看/dev/shm: 发现设置了7G&#xff0c;操作系统是512G&#xff0c;正常情况下/dev/shm应该是操作系统的一半&#xff0c;修改为250G后数据库…

微信小程序 django+nodejs电影院票务售票选座系统324kd

小程序Android端运行软件 微信开发者工具/hbuiderx uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 前端&#xff1a;HTML5,CSS3 VUE 后端&#xff1a;java(springbootssm)/python(flaskdja…

vue3:菜单、标签页和面包屑联动效果

文章目录 1.整体思路2.实现过程 概要 提示&#xff1a;这里可以添加技术概要 例如&#xff1a; openAI 的 GPT 大模型的发展历程。 1.整体思路 在之前做的后台项目中&#xff0c;菜单、标签页和面包屑之间的联动&#xff0c;自己都是通过在路由前置守卫中&#xff0c;定义b…