当前位置: 首页 > news >正文

Linux 基础IO——重定向和缓冲区

目录

一、重定向

1、重定向的本质

2、使用 dup2 系统调用 

(1)输出重定向 

(2)追加重定向 

  (3) 输入重定向 

​ 二、缓冲区

1.理解缓冲区

2.缓冲区刷新问题

3.为什么要有缓冲区?

4.这个缓冲区在哪里?


一、重定向

什么是重定向,是本来写到显示器上的内容写入到文件当中。

其中, fd = 1 。这种现象叫做输出重定向。常见的重定向有:>,>>,<

1、重定向的本质

重定向的本质其实就是在 OS 内部更改 fd 对应的内容指向。也就是本该写入到1号文件描述符的内容都写到了log.txt中。

 1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <sys/types.h>
  4 #include <sys/stat.h>
  5 #include <fcntl.h>
  6 
  7 int main()
  8 {
  9   close(0);
 10   int fd =open("log.txt",O_RDONLY);
 11   if(fd<0)
 12   {
 13     perror("open");
 14     return 1;
 15   }
 16   printf("fd:%d\n",fd);
 17   char buffer[64];
 18   fgets(buffer,sizeof buffer,stdin);                                                                                                         
 19   printf("%s",buffer);
 20   return 0;
 21 }

 

本应该从键盘读取的内容,现在从 log.txt 中读取。这就叫作输出重定向。 

 

 

本应该从显示器上读取,现在从log.txt中读取,这是输入重定向。 

 

这是追加重定向。

2、使用 dup2 系统调用 

 

这个oldfd和newfd我们该怎么区分呢?

很明显依靠函数原型,我们就能认为 dup2(1, fd),因为 1 是先打开的,而 fd 是后打开的.可实际上并不是这样的,文档中说 newfd 是 oldfd 的一份拷贝,这里拷贝的是文件描述符对应数组下标的内容,所以数组内容最终应该和 oldfd 一致。

换而言之,这里就是想把让 1 不要指向显示器了,而指向 log.txt,fd 也指向 log.txt。所以这里的 oldfd 对应 fd,newfd 对应 1,所以应该是 dup2(fd, 1)。

我们最后的文件描述符要跟oldfd一致。

dup(3,1)是把三号文件描述符的内容拷贝到一号文件描述符里。

(1)输出重定向 

  •   < 就是 dup2(fd, 0),且 open 文件的方式是 O_RDONLY;

(2)追加重定向 

 

  (3) 输入重定向 

无非是在追加重定向基础上更改

 二、缓冲区

1.理解缓冲区

先看一段代码

  • 当我们去掉换行,关闭1号文件描述符时,显示器和重定向到文件都显示不了内容。
  • 只有write的时候,也关闭了1号文件描述符,显示器和重定向到文件却能显示。

这是为什么呢?

这是因为存在缓冲区,C库函数接口没带"\n",没有打印到显示器上,先写到了缓冲区上 。

这个缓冲区一定不在操作系统内部!不是系统级别的缓冲区!

write系统调用接口,使用系统内核的缓冲区,进程结束的时候直接刷新到磁盘上。

而printf/fprintf/fwrite...等C库函数,并没有把数据写入到系统级别的缓冲区中,C语言会提供一个缓冲区(这叫应用层缓冲区,也是用户级缓冲区),会先把数据写入到用户级缓冲区里。再调用write系统调用接口,在合适的时候把用户级缓冲区的内容写入到系统缓冲区里。

可这段代码中,执行到close(1)时,还没有调用write讲数据写入到1号文件描述符,就把对应的显示器文件描述符关闭了,此时的数据还在用户级缓冲区,刷新时显示不出来。

 

我们再来看一段代码

 结果如下:

同样一个程序,向显示器打印输出 4 行文本,而向普通文件(磁盘)上打印输出 7 行文本。其中,printf 和 fwrite (库函数)都输出了 2 次,而 write 只输出了一次(系统调用),为什么呢?

2.缓冲区刷新问题

我们先给大家讲解缓冲区刷新

  1. 当进程退出的时候,直接刷新。
  2. 无缓冲区——直接刷新。
  3. 行缓冲区——不刷新,直到遇到了\n才刷新。
  4. 全缓冲区——直到缓冲区满了才刷新。
  • 我们的显示器文件的刷新方案就是行刷新,所以在printf函数遇到\n会直接刷新到显示器中。
  • 讲数据写入到普通文件是全缓冲区刷新,数据写满缓冲区才刷新。或者写完了数据,进程退出了也会刷新。 

我们再重回刚刚的问题:

在向显示器打印输出是是行刷新,遇到了\n就刷新,所以我们在上面写入的4个接口的内容能直接打印到显示器上。

而写入到文件时全刷新,当缓冲区满了或者进程结束了才刷新。

这段代码依次往下执行,printf/fprintf/fwrite这三个是C库函数写入到C缓冲区中,等待合适的时候调用write系统调用接口写入系统缓冲区中,执行到write时,因为write是直接写道系统缓冲区,所以被直接刷新到显示器上,所以优先打印出hello write 

再往下执行到fork时,此时数据还在C缓冲区中,但是 fork 的时候,父子数据会发生写时拷贝,所以当你父进程准备刷新的时候,子进程也就有了同样的一份数据,随即产生两份数据。 从而导致C库函数被打印了两次。

3.为什么要有缓冲区?

  •  解决了效率问题,在printf/fwrite把数据放入缓冲区中直接返回了。
  • 语言配合的格式化(输入、输出的转换),我们写在显示器上,123,这个123是字符1字符2字符3。我们写int a=10; printf("hello%d\n",a); 打印的是整数。这个时候就需要缓冲区进行类型的转化。

4.这个缓冲区在哪里?

我们之前说文件操作系统离不开FILE struct,FILE结构体里面还有对应打开文件的缓冲区字段和维护信息。

每一个文件都对应一个语言缓冲区。

我们打开10个文件,有10个文件描述符,也就有10个对应的语言缓冲区。 

FILE对象是属于用户还是操作系统呢?

属于用户,因为语言都属于用户,FILE内有语言缓冲区。

相关文章:

  • learn_pytorch03
  • 8、k8s的pv和pvc
  • MATLAB中contains函数用法
  • TLQ-CN10.0.2.0 (TongLINK/Q-CN 集群)部署指引 (by lqw)
  • 《探秘Downpour SGD算法:原理与多元应用场景解析》
  • 基于角色访问控制的UML 表示
  • 网络营销新宠:http代理ip为广告投放精准定位保驾护航
  • 网络安全中的account和audit区别
  • 变频器MODBUS RTU通信
  • Nginx 之Rewrite 使用详解
  • 若依 ruoyi-vue 隐藏字典样式
  • Excel常用操作
  • 算法之 跳跃游戏
  • Java进阶,时间与日期,包装类,正则表达式
  • 学习《人工智能的未来》这本书中的恒定表征概念:恒定表征和变化的恒定表征
  • Ubuntu20.04桥接网络和静态IP配置
  • 通过 Docker 安装和部署 KeyDB v6.3.4 的详细步骤
  • elementui: el-dialog的header设置样式不生效
  • Python PyCharm DeepSeek接入
  • 机器学习:朴素贝叶斯
  • 网站推广营销联系方式/淘宝指数查询官网
  • 外贸网站流量/网站免费网站免费
  • 网站建设费 无形资产/软文推广页面
  • 合肥有多少建网站公司/谷歌浏览器手机版
  • 做盗号网站/《新闻联播》 今天
  • 淘客怎么做网站单页/沈阳网页建站模板