重定向、缓冲区详解

目录

一、重定向

二、缓冲区

1、缓冲区现象

2、理解缓冲区

3、stderr是什么?

4、相关知识


一、重定向

文件描述符的分配规则:查看自己的文件描述表,分配最小的没有被使用的fd

重定向的本质:是在内核中改变文件描述符表
特定下标的内容,和上层无关

重定向的本质:是在内核中改变文件描述符表特定下标的内容
至于,你这个下标指向什么位置,和我重定向无关,我只认这个下标
所以,事实上,要做重定向,是两个文件描述符指向的文件的改变
所以,需要操作系统提供一个专门用于文件描述符改向的系统调用
这个系统调用就叫做dup2

#include <unistd.h>

int dup2(int oldfd, int newfd);

参数
oldfd:原始文件描述符,表示要复制的文件描述符。
newfd:目标文件描述符,表示将 oldfd 复制到的文件描述符。

返回值
成功时,dup2 返回 newfd,这是复制操作后新的文件描述符。
失败时,返回 -1,并将 errno 设置为相应的错误代码。

把oldfd复制到newfd

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd;

    // 打开文件,如果文件不存在则创建,权限为0644
    fd = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (fd < 0) {
        perror("open");
        return 1;
    }

    // 将标准输出重定向到fd
    int ret = dup2(fd, STDOUT_FILENO);
    if (ret < 0) {
        perror("dup2");
        return 1;
    }

    // 关闭原文件描述符
    close(fd);

    return 0;
}

>:将命令的标准输出重定向到文件,会覆盖文件内容。

示例:

ls > file.txt 将 ls 命令的输出写入 file.txt 文件中,覆盖原有内容。

<:将文件内容作为命令的标准输入。

示例:

sort < input.txt 将 input.txt 文件的内容作为 sort 命令的输入进行排序

>>:将命令的标准输出重定向到文件,追加到文件末尾。

示例:

echo "Hello" >> greetings.txt 将 "Hello" 追加到 greetings.txt 文件的末尾。

二、缓冲区

1、缓冲区现象

​
#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <stdlib.h>
 int main()
 {
 close(1);
   int fd = open("myfile", O_WRONLY|O_CREAT, 00644);
   if(fd < 0){
       perror("open");
       return 1;
   }
 printf("fd: %d\n", fd);
 //fflush(stdout);
   close(fd);
 exit(0);
 }

​

当运行上述代码时,
在没有fflush函数之前,即使对一个文件写入了内容,也没有显示
但是使用了fflush函数之后,就显示了
这是为什么?

原因:
struct FILE 结构体内还有一个语言级别的文件缓冲区
你使用的printf、fprintf函数等
写入的数据,都是写到了语言级别的文件缓冲区
而不是在内存的缓冲区
所以,fflush函数所作的工作,其实就是把语言级别的缓冲区,
刷新到内存中
如果在文件关闭之前,没有进行刷新,
那么,就无法把语言级的缓冲区刷新到内存

上述的代码中,把1文件(标准输出,显示器)关闭后,再新建一个myfile文件,他的fd会被分配到1,因为1是空着的。此时,我把信息写入到myfile文件内,即fd为1的文件,此时,只是写到了myfile语言级缓存内,还没有刷新到内存中。可是,我们的操作系统还没有来得及刷新,代码就跑完了,直接close掉文件,我们就无法进行刷新。

2、理解缓冲区

缓冲区区分:用户级缓冲区 和 内核级缓冲区

其缓冲区的作用是:提高效率(提高使用者的效率)

例如说,当我们使用c语言的函数接口时
数据会存在语言级的缓冲区内
而不会立马刷新到内存,而是在合适的时机再刷新到内存
在用户的角度来看,速度就快了
同时,调用系统调用是有成本的
所以,尽量少调用,以提高效率
那么怎么办呢?
其采取的策略是,
你调用了多次c语言函数接口
此时,就会积攒数据在语言级的缓冲区内
然后,再调用一次系统调用接口
将所有数据全部刷新到内存中(文件内级的缓冲区)
这样,就提高了整体的效率
提高了使用者的效率,也提高了硬件IO的效率

这就好比顺丰快递
快递不是一件一件的寄送,因为发送快递是有成本的
所以要积攒到一定数量,一车一车的送

所以,什么是缓冲区?
就是一段内存空间

为什么会有缓冲区?
存在的目的就是提高效率
给上层提供良好的IO体验
间接提高整体的IO效率

缓冲区如何提高效率?
(1)刷新策略
立即刷新(可以认为是无缓冲),如fflush(stdout)和 fsync(int fd)函数,都是立即刷新到外设
行刷新:显示器(照顾人的查看习惯,人习惯一行一行的看文字)

全缓冲:缓冲区写满才刷新,普通文件

(2)特殊情况

进程退出,系统会自动刷新缓冲区
强制刷新

3、stderr是什么?

为什么要默认打开0,1,2?

我们写的程序,本质都是对数据的处理(计算、存储...)
那么数据从哪里来?
数据去到哪里?
所以,为什么有0 和 1?
为了解决用户更好的动态获取数据的来源、去处、状态等信息
所以,默认把0 和 1打开
可是,为什么有2呢?
我们打印的信息,会有错误的信息和正确的信息
我们就可以用重定向把正确的和错误的信息分开
方便查看错误
常用的perror这个函数
就是往2文件内打印,而不是1

完整的重定向语法:把1的信息输入到ok.log,2的信息输入到err.log

./a.out 1>ok.log 2>err.log

4、相关知识

系统调用是直接刷新到文件内核的缓冲区
注意,并不是直接刷新到硬件磁盘上

缓冲区在哪? 
在FILE结构体内部
每一个文件都有自己的FILE*结构体,每一个文件都有自己的缓冲区

c语言为什么要在FILE结构体提供用户级缓冲区?
为了减少底层调用系统调用的次数,让使用C语言的IO函数(printf、fprintf等)效率更高 

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二十5画生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值