2.重定向
2.1.输出重定向
1.输入重定项。
我们之前学习过的输出重定向就是,将我们本应该输出到显示器上的数据重定向输出到另一个文件中。那他的原理是什么了?
例如: 如果我们想让本应该输出到“显示器文件”的数据输出到log.txt文件当中,那么我们可以在打开log.txt文件之前将文件描述符为1的文件关闭,也就是将“显示器文件”关闭,这样一来,当我们后续打开log.txt文件时所分配到的文件描述符就是1。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(1);
// 打开文件
int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
{
perror("open");
exit(1);
}
// 打开成功
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
printf("fd: %d\n", fd);
fprintf(stdout, "hello fprintf\n");
const char* s = "hello fwrite\n";
fwrite(s, strlen(s), 1, stdout);
fflush(stdout);
// 关闭文件
close(fd);
return 0;
}
通过上面的现象也可以看出,打印的数据没有到显示器上,而是到了磁盘的文件中,这是为什么呢?
上面就说过,0、1、2默认是被打开的,对应的就要打开显示器,所以stdout的文件描述符就是1,所以C语言的接口fprintf认识的就是stdout或者说就是1,我们一开始就关闭了1号文件描述符,把数组下标为1的位置设置为NULL,然后打开了log.txt文件,此时1没有被占用,所以就把下标为1的位置填入log.txt的结构体的地址,log.txt的文件描述符就是1了,但是上层的C语言函数认识的还是1,他们还是继续往1中写入,这样就不能打印到屏幕而是重定向到了文件中。
重定向的本质是在操作系统中更改fd对应的内容,上面演示的这就就叫做输出重定向。
2.2.输入重定向
输入重定向就是,将我们本应该从一个键盘上读取数据,现在重定向为从另一个文件读取数据。
比如说我们的fget函数是从标准输入读取数据,现在我们让它从log1.txt当中读取数据,我们在scanf读取数据之前close(0).这样键盘文件就被关闭,这样一样log1.txt的文件描述符就是0.
int main()
{
close(0);
// 打开文件
int fd = open("log.txt", O_RDONLY);
if (fd < 0)
{
perror("open");
exit(1);
}
printf("fd: %d\n", fd);
char buffer[64];
fgets(buffer, sizeof(buffer), stdin);
printf("%s\n", buffer);
// 关闭文件
close(fd);
return 0;
}
关闭了0号文件描述符,所以打卡的新文件的文件描述符就变成了0,然后读取了文件中的第一行数据。
2.3.追加重定向
还有一种就是追加重定向,更改一下选项就行了。
int main()
{
close(1);
// 打开文件
int fd = open("log.txt", O_WRONLY | O_APPEND | O_CREAT);
if (fd < 0)
{
perror("open");
exit(1);
}
printf("%d\n", fd);
fprintf(stdout, "append success\n");
fflush(stdout);
// 关闭文件
close(fd);
return 0;
}
【注意】:“>”输出重定向修改的只是1号也就是stdout标准输出,所以尽管程序中有两行代码,一行向1号文件描述符中打印,另一行向2号文件描述符中打印,那么使用输出重定向只会使1号文件描述符重定向,2号还是打印到显示器上。
2.4.dup2
我们发现我们上面只能通过close关闭对应的文件描述符实习对应的输出重定向和输出重定向,那我们能不能不关闭呢?
要完成重定向我们只需对fd_array数组当中元素进行拷贝即可。
例如,我们若是将fd_array[3]当中的内容拷贝到fd_array[1]当中,因为C语言当中的stdout就是向文件描述符为1文件输出数据,那么此时我们就将输出重定向到了文件log.txt。而在linux当中就给我们提供了这个系统调用:
- 函数功能: dup2会将fd_array[oldfd]的内容拷贝到fd_array[newfd]当中。
- 函数返回值:调用成功返回0,失败返回-1
使用的过程中需要注意:
- 如果oldfd不是有效的文件描述符,则dup2调用失败,并且此时文件描述符为newfd的文件没有被关闭。
- 如果oldfd是一个有效的文件描述符,但是newfd和oldfd具有相同的值,则dup2不做任何操作,并返回newfd。
只需要把想要重定向的文件在数组中拷贝过去,比如我想要输出重定向,重定向到某个文件,那么1就代表标准输出,所以就要改变1的指向,就把3的地址拷贝过去,这样1就指向了重定向的文件。
输入重定向也是一样的,0是标准输入,就要从其他文件输入,就把其他文件的地址拷贝到0的位置。
下面通过dup2演示一下前面的输出重定向:
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<sys/stat.h>
4 #include<unistd.h>
5 #include<fcntl.h>
6 int main()
7 {
8 int fd=open("./log.txt",O_WRONLY|O_CREAT,0644);
9 dup2(fd,1);
10 printf("hello world\n");
11 printf("hello world\n");
12
13 }
2.5.重定向的本质
重定向的本质,其实是在OS内部,更改fd对应的内容的指向!!