文章目录
- IO重定向
- 概念
- 3个标准文件描述符
- “最低可用文件描述符”原则
- 默认的连接:tty
- 使用close then open将stdin定向到文件
- 使用open..close..dup..close将stdin定向到文件
- 使用open..dup2..close将stdin重定向到文件
- 课上实验
IO重定向
- 大多数的程序不接收输出文件名
- 一般情况下将结果写到文件描述符
1
,并将错误消息写到文件描述符2
。
- 一般情况下将结果写到文件描述符
- 如果希望将进程的输出写到文件或另一个进程的输入去,就必须
重定向
相应的文件描述符。
概念
1.Unix进程使用文件描述符0,1,2作为标准输入、输入和错误的通道
2.当进程请求一个新的文件描述符时,系统内核将最低可用的文件描述符赋给它。
3个标准文件描述符
所有Unix都使用三种流的模型。
此模型通过一个简单的规则来实现。
三种流的每一种都是一个特别的文件描述符。
所有的Unix工具都使用文件描述符0,1,2
- 标准文件描述符
0: stdin
1: stdout
2: stderr
“最低可用文件描述符”原则
- 文件描述符的概念:是一个数据的索引号。
- 每个进程都有其打开的一组文件,这些打开的文件被保持在一个数组中。
- 文件描述符即为某文件在些数组中的索引。
“最低可用文件描述符”原则:
当打开文件时,为此文件安排的描述符总是此数组中最低可用位置的索引。
默认的连接:tty
- 通常通过shell命令运行Unix系统工具时,
stdin
、stdout
和stderr
已连接在终端上。
因此系统工具从键盘读取数据并把输出和错误消息写到屏幕。
大部分的Unix工作处理从文件或标准输入读入的数据。
如果在命令行上给出了文件名,工具将从文件读取数据。若无文件名,程序则从标准输入读取数据。
shell并不将重定向标记和文件名传递给程序,即重定向I/O的是shell而不是程序
重定向可以出现在命令行中的任何地方,并且在重定向标识符周围并不需要空格来区分
shell提供对重定向其他文件描述符的支持。
如: 2>file2,即重定向文件描述符2,将标准错误输出到给定的文件中
使用close then open将stdin定向到文件
-
开始时,系统采用典型设置
- 输入的数据流经过文件描述符0,输出流经过文件描述符
1和2
- 输入的数据流经过文件描述符0,输出流经过文件描述符
-
第一步:close(0),将标准输入的连接挂断。
文件描述符数组中的第一个元素处于空闲状态。 -
第二步,使用open(filename, O_RDONLY)打开一个想连接到stdin上的文件。
- 当前最低可用文件描述符为0,因此打开的文件将被连接到标准输入上去
-
示例代码:
main()
{
int fd ;
char line[100];
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
close(0);
fd = open("/etc/passwd", O_RDONLY);
if ( fd != 0 ){
fprintf(stderr,"Could not open data as fd 0\n");
exit(1);
}
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
}
stdinredir1从标准输入读取并打印了三行字符串
接着重定向标准输入
之后从重定向的标准输入中读取并打印了三行字符串
使用open…close…dup…close将stdin定向到文件
-
第一步:open(file)
- 打开stdin将要重定向的文件。这个调用返回一个文件描述符,这个文件描述符不是0
-
第二步:close(0)
- 将文件描述符0关闭
-
第三步:dup(fd)
- 系统调用dup(fd)对文件描述符fd进行复制。此次复制使用最低可用文件描述符号。
-
第四步:close(fd)
- 关闭文件的初始连接,只留下文件描述符0的连接。
-
示例代码
#include <stdio.h>
#include <fcntl.h>
main()
{
int fd ;
int newfd;
char line[100];
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
fd = open("/etc/passwd", O_RDONLY);
close(0);
newfd = dup(fd);
if ( newfd != 0 ){
fprintf(stderr,"Could not duplicate fd to 0\n");
exit(1);
}
close(fd);
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
}
使用open…dup2…close将stdin重定向到文件
-
将 close(0)和dup(fd)结合在一起作为一个单独的系统调用dup2。
dup2(old, new)将文件描述符old复制到文件描述符new。close(0); newfd = dup(fd);
替换为
newfd = dup2(fd,0);
即可。
课上实验
- 使用dup或dup2,结合open/read/write/lseek实现标准输入或标准输出重定向
标准输入流重定向:我们将默认从终端的输入流改为从文件读取的输入流。
代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
main()
{
int fd ;
int newfd;
char line[100];
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
fd = open("/etc/passwd", O_RDONLY);
close(0);
newfd = dup(fd);
if ( newfd != 0 ){
fprintf(stderr,"Could not duplicate fd to 0\n");
exit(1);
}
close(fd);
fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line );
}
标准输出流重定向:将默认标准输出流改为某个文件
代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
main()
{
int fd ;
int newfd;
fd = open("abc.txt", O_WRONLY|O_CREAT|O_TRUNC,0644);
close(1);
newfd = dup(fd);
if ( newfd != 1 ){
fprintf(stderr,"Could not duplicate fd to 1\n");
exit(1);
}
close(fd);
char line[]="我是标准输出,默认输出到终端,但我被重定向了,将被打印在重定向的位置";
write(1,line,strlen(line));
close(newfd);
}
- 分析:
标准输出流卡了我很久,因为我每次重定向后abc.txt文件内容后面都会有一段乱码,像内存泄露一样乱码出现在abc.txt文件中,可当我将open的模式由O_WRONLY改为O_WRONLY | O_CREAT | O_TRUNC时,才能达到理想实验结果。总之使用 open(“abc.txt”, O_WRONLY | O_CREAT | O_TRUNC, 0644) 更为全面,既能确保文件不存在时创建它,又能确保在打开时清空文件内容,还可以设置新创建文件的权限。
结果如下: