【Linux】认识文件(二):重定向
上篇文件博客中,讲了进程管理已打开文件的方式,这次带来重定。
想要理解重定向的原理的话,需要对文件标识符有一定的认识
所以推荐没看过的把上篇给看了,文件标识符
一.stdout,stderr,stdin
再讲重定向之前,需要讲一下这三个是啥东西。
上篇博客我们说了,一个进程能打开多个文件
这三个可以说是每个进程最先打开的文件
这个是操作系统要求的
这个时候需要用一下上篇博客的内容
一个进程是通过这个来管理自己打开的文件的。
而进程最先打开的文件就是这三个:
- 标准输入【键盘文件】(stdin)的文件描述符标识符是 0
- 标准输出【显示器文件】(stdout)的文件描述符标识符是 1
- 标准错误【显示器文件】(stderr)的文件描述符标识符是 2
同时可以在调用文件标识符参数的函数中进行使用
#include<unistd.h>
int main()
{
char* message="asdasd";
write(1,message,strlen(message));
}
这里面的1指的就是显示器文件。
这里细心的人可能发现了:
stderr和stdout都是显示器
确实是这样。
但是:
stderr是专门用来输出错误信息的。
stdout是专门用来输出结果的
一般人也不会喜欢错误信息和结果全都输出到一个文件里吧
所以把这两个进行了分离
二.重定向
1.什么是重定向
最开始我们肯定要先了解什么是重定向。
官方术语:在计算机系统中,重定向是一种机制,用于将一个程序的输入或输出从一个默认位置或设备重新定向到另一个位置或设备。这种机制可以改变程序的数据流方向,使其与其他组件或资源进行交互。
这么长一串看起来还挺磨人的,所以这里下面就直接上:
命令行中的重定向操作
大伙应该都已经用过这几个了
所以就随便演示一下操作,主要是让大家明白啥是重定向
i.输出重定向>
这里我们其实就能理解啥是重定向了,
ls > test.log
这里原本ls,是要输出到显示器中的
但是加上> test.log
后,将这个结果输出到了test.log中了
就是将文件的输出结果转向到了另一个文件中
ii.追加重定向>>
这个就是不将文件中的原数据清空,在后文进行添加,相当于特殊用法的输出重定向
iii.输入重定向<
不光是输出和追加能重定向
输入也能重定向
这里如果直接用cat,它是专门等待用户在stdin文件的输入,然后输出到stdout文件中
但是用了< test.log
后,它会直接将test.log的内容当做输入,然后进行打印
2.重定向原理
上面的只是bash命令行的重定向命令
接下来要前往底层进行了解重定向
这里我们可以看看重定向的相关表现
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<string.h>
#include<unistd.h>
int main()
{
const char* message="lalala";
close(2);
int fd=open("test.log",O_RDWR);
write(2,message,strlen(message)-1);
}
这个代码能看到
把代表sterr的2的文件标识符关闭后
接下来用write将message塞进文件标识符2中。
我们在程序结果中能看到:
发现这里write对FD2的文件进行输入,这里是test.log接收到了
所以说这个时候test.log的FD是2
这里就应该来讲讲
文件描述符对应的分配规则 :
从0下标开始,寻找最小的没有使用过的数组位置,它的下标就是新文件的文件标识符
所以这里就能猜到原因了:
这是因为将一号文件标识符(stderr)关闭后,test.log代替了原本stderr的位置
大致就是这个原理
3.dup2的使用
通过上面的操作,如果要实现重定向,就要将文件一直开启关闭
这个想想就麻烦
所以操作系统自己提供了一个重定向的接口
所以就有了dup接口,来让用户进行重定向
dup2函数的作用是将文件描述符oldfd复制到newfd,并返回新的文件描述符。
对这里没看错,是把oldfd复制给新的newfd
所以是:
大致是这样的用法:
这里要注意:
dug拷贝的不是文件标识符,文件标识符只是个下标
拷贝的是数组中的对应文件标识符中的文件地址
三.理解linux中的一切皆文件
可能之前大家或多或少听说过这句话
但是可能理解的不是很透彻
可能只听说过,在Linux中各种硬件设备,本质上都是文件
确实是这样,
这里就慢慢带大家来更加清楚了解一下
这里有各种硬件,他们都有各自的相关功能接口
这里能发现各个硬件都有类似的访问接口
特别是读写(I/O)功能
利用各个硬件的读写功能实现方式不一样,但是他们包含的功能是相似
这个特点,我们就可以想到:
设计一个专门的功能集合结构体,然后给不同的硬件对应到各自的操作中
这里给各个硬件创建相同的功能集合体
然后分别对应他们各自的功能接口
接下来就可以创建文件结构体了,将硬件都用文件进行表示
这里我们能发现:
只要在文件结构体中,塞进一个能找到对应功能集合体的指针
,就大功告成了
这样就完成了通过文件操作硬件的方式
接下来来对文件的管理我们就很熟悉了
大致是:
进程结构体->进程管理文件的结构体数组加上对应的文件标识符号->对应的文件->对应的功能集合体->硬件对应的操作接口
大致差不多是这样。
这里其实就能看到面向对象变成思想的影子了