重定向
重定向有三种类型:输出重定向、追加重定向、输入重定向
问题:重定向的效果是什么?
输出重定向:将本应该打印到 显示器 的内容输出到了指定的文件中。
追加重定向:将本应该打印到 显示器 的内容追加式的输出到了指定的文件中
输入重定向:将本应该从 键盘中 读取的内容改为从指定的文件中读取。
重定向的原理
当我们使用C库函数的时候,实际上就是在调用系统调用接口。
FILE* fp = fopen();
这里fp指针,实际上是指向了一个FILE结构体变量的。而FILE结构体变量中则是封装了fd,也就是文件描述符。不了解文件描述符的可以看看这篇文章
struct FILE{
int _fileno; //封装的文件描述符 fd
}
像我们知道的默认打开的3个流,stdin、stdout、stderr。 他们都是FILE* 类型的,也都分别指向一个FILE对象。
FILE* stdin --> FILE (fd = 0)
FILE* stdout --> FILE (fd = 1)
FILE* stderr --> FILE (fd = 2)
当我们使用printf、fprintf、fputs一类函数时,如果将文件描述符fd=1 (输出流stdout) 关闭。那么下次我们打开新文件时,就会使用fd = 1 (遵守文件描述符的分配规则)。而上面这些C库函数默认使用的就是stdout,也就是fd = 1。此时他们就会将输出打印到我们新打开的文件当中了。这就是输出重定向。
重定向的本质是:修改文件描述符fd下标 对应的struct file * 的内容 (将其换成目标文件的地址)。
输出重定向
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main()
{
close(1); //关闭显示器
umask(0);
int fd = open("file.txt", O_WRONLY | O_CREAT, 0666);
const char* buffer = "Write some words to file.txt\n";
write(fd, buffer, strlen(buffer));
close(fd);
return 0;
}
追加重定向
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main()
{
close(1); //关闭显示器
int fd = open("file.txt", O_WRONLY | O_APPEND);
const char* buffer = "Append some words \nto the end of file\n";
write(fd, buffer, strlen(buffer));
close(fd);
return 0;
}
输入重定向
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main()
{
close(0); //关闭键盘
int fd = open("file.txt", O_RDONLY);
char buffer[256]; //保证空间足够大
ssize_t num = read(fd, buffer, sizeof(buffer)); //read的返回值返回实际读到的个数
buffer[num] = '\0'; //这里必须给结尾添加'\0',不然打印的时候就会出乱码
cout << buffer;
close(fd);
return 0;
}
重定向函数dup2
int dup2(int oldfd, int newfd);
参数:
oldfd:你新打开的文件
newfd:你想要重定向到的目标文件
//这里的old和new比较有干扰性…
//我们想要进行输出重定向就dup2(fd, 1); 输入重定向就dup2(fd, 0);
问题:使用dup2的优势在哪里?dup2比我们自己实现的重定向有什么区别?
dup2是可以指定重定向到哪里的。我们刚才利用文件描述符的规则进行重定向,先关闭一个我们想要重定向到的文件所对应的文件描述符,再打开新的文件,此时的新文件就用了刚才关闭的文件描述符。这种方法虽然是可行的,但是当你同时打开多个文件的时候,不好控制。因为你必须在关闭文件之后,立刻打开新的文件。而使用dup2完全不需要考虑这些,只需要知道你要重定向到哪个文件就行了。
演示
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
using namespace std;
int main()
{
int fd = open("file.txt", O_RDONLY);
dup2(fd, 0);
char buffer[256];
ssize_t num = read(fd, buffer, sizeof(buffer));
buffer[num] = '\0';
cout << buffer;
return 0;
}