文件的打开
要先了解重定向,就要对文件打开本质有一个基础的了解。
1.文件也是有属性的,打开时间,修改时间,大小等,可以认为文件就是内容加属性。
2.那么要打开文件,肯定也要像程序那样加载到内存吧,但是文件加载进来,就必须要住址管理。
3.linux里面有一种struct_file(假设叫这个,内核里面不一定取这个名字)结构体去管理加载进内存的文件。
来看下linux里面打开文件的系统接口:open
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
void Test_Open()
{
//umask(0);you can change the umask by umask
//creat and write ,
int fd = open("log.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
int fa = open("loga.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
int fb = open("logb.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
int fc = open("logc.txt",O_WRONLY | O_CREAT | O_TRUNC,0666);
if(fd<0)
{
perror("open");
return ;
}
printf("%d\n",fd);
printf("%d\n",fa);
printf("%d\n",fb);
printf("%d\n",fc);
const char* msg = "hello file system call\n";
write(fd,msg,strlen(msg));
close(fd);
}
在linux里面去调上面这个函数,能打开(没有就生成)4个文件分别是loga.txt···
在其中log.txt里面是可以看见。
hello file system call
这个就是linux打开文件的系统调用了。
上面是open的手册,open有两个,可以是三个或者两个参数。
其返回值被称为fd,(filedirection,一般叫做文件标识符)。
第一个参数是打开文件二点路径,第二个参数是打开方式,如英文的含义,第三个参数是如果在有创建文件的时候才给,如果没有创建,mode参数就会被忽略,其就是传输创建文件的权限,一般传输八进制数字。(如0666)
这里解释下fd,为什么文件标识符会是个int?本质是因为,操作系统内核每打开一个文件,都会有一个结构体去管理,这个之前提过,并且有一个struct_file*数组来村这些指针,而这个fd呢,就是用来指向里面的。
从上面代码多次运行结果,来看,每次打开都是从3开始增长的文件标识符,并且是依次增长,按理来数组应该是从0开始增长。
如下代码是可以验证上述的。
原因是:C语言默认打开了三个执行流:0-----标准输入流,1-----标准输出流,2-----标准错误
我们知道linux里面一切皆文件,三个输入流也是如此,所以是默认打开了这三个文件。
void CloseFD_0()
{
//这里我们可以看见,返回的文件指示数,选取当前最小的,
//read的0被我们手动关闭之后,就变成是0了
//默认打开了,0,1,2,stdin,stdout,stderro
close(0);
int filedirection = open(filename,O_CREAT |O_TRUNC,0666 );
if(filedirection<0)
{
return ;
}
printf("filedirection:%d\n",filedirection);
close(filedirection);
return ;
}
重定向
接下来讲下重定向,什么是重定向?英文但此时Redirection,其实就是指的FileDirection的重定向。
也就是说改变File direction这个文件指示符下标所指向的内容.linuxC语言里面提供了dup来更换fd所指向数组的内容,替换调指针以达到重定向的目的。
执行下面函数:重定向了标准输出到log.txt,打印到标准输出内容的会打印到log.txt里面,如printf就是向标准输出打印。
const char* filename = "log.txt";
void Redirect_Out()
{
//清空文件重定向
// int fd= open(filename,O_WRONLY | O_TRUNC | O_CREAT,0666);
//追加重定向
int fd = open(filename,O_WRONLY |O_CREAT | O_APPEND,0666);
if(fd<0){
perror("open fail");
return ;
}
dup2(fd,1);
printf("hello redirect\n");
close(fd);
return ;
}
重定向里面说,把A重定向到B,其实就是把A的fd所指向的内容替换成B的fd所指向的指针。即把原来文件标识符指向的那个structfile*的指针替换成对应目标文件的指针即使重定向到什么文件了。
bash的重定向
#include <iostream>
using namespace std;
int main()
{
cout<<"this is stdin"<<endl;
cerr<<"this is stderror"<<endl;
return 0;
}
编译上述代码,得到a.out可执行文件之后。
./a.out 1 > log.txt 2>cerr.txt
执行这个命令就能得到对应的两个文件,你会发现标准输出和标准错误分别就定义到了两个文件了。
还有种不是很常规的写法,把标准输出重定向为log.txt,这个时候1就是指向的log.txt,但是1又被重定向指向了2,所以这个时候会直接通过标准错误打印信息到屏幕上,而log.txt里面什么也不会有。
./a.out 1>log.txt 1>&2