C 语言 数据流和重定向
1.1 数据流
数据流:就是流动的数据,数据从一个进程流出,流入另一个进程,除了标准输出,标准输入,标准错误外还有其他形式的数据流,如文件连接,网络连接。
进程含有:
- 正在运行的程序
- 堆和栈数据空间
- 记录数据流的方向
1.2 文件描述符
进程用文件描述符表示数据流, 是一个数字,代表一条数据流。把文件描述符和对应的数据流保存到描述符表中。这张表长这个样:
前三项一直不变:
0
: 标准输入1
: 标准输出2
: 标准错误
其他项要么空,要么是进程打开的数据流。
1.3 重定向
重定向:替换数据流, 标准输入/输出/错误在描述符表中的位置是固定的,但它们指向的数据流可以改变。也就是说,如果想重定向标准输出,只需要修改表 中 1 号描述符对应的数据流就行了。
所有向标准输出发送数据的函数会先查看描述符表,看 1 号描述符指向哪条数据流,然后再把数据写到这条数据流中,printf() 便是如此。
1.4 对文件描述符的操作
有如下相关函数:
fileno()
: 返回描述符号dup2()
: 复制数据流
1.4.1 fileno()
1.4.2 dup2()
1.4.3 实例:rss 源检索输出到文件中
还是上一章节的例子,只有一个 rss 源:
#include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> //定义一个通用的错误处理方法 void error(char *msg){ fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(1); // exit(1) 会立刻终止程序并把`退出状态`设为 1 } int main(int argc, char *argv[]) { char *phrase = argv[1]; char *vars[] = {"RSS_FEED=http://rss.news.sohu.com/rss/guoji.xml", NULL}; //打开文件 FILE *f = fopen("output.txt", "w"); //判断打开文件是否成功 //如果不能以写的方式打开,则`f=0` if (!f) { error("文件 output.txt 打开失败"); } //fork 进程 pid_t cf = fork(); //判断 fork 是否成功 if (cf == -1) { error("fork 进程失败"); } //这段代码会修改子进程,因为 pid 为 0 if (!cf) { //重定向,让 1 号描述符指向 output.txt 文件 if (dup2(fileno(f), 1) == -1) { error("重定向失败"); } //执行系统调用 int pid = execle("/usr/bin/python", "/usr/bin/python", "./rssgossip.py", phrase, NULL, vars); if (pid == -1) { error("系统调用失败"); } } return 0; }
我们运行下代码:
./rss sohu cat output.txt
如果幸运的话,里面会看到内容,这里我故意放慢 rssgossip.py 运行, 加上了 time.sleep(3)
,让它 3s 后才开始处理。你会看到 output.txt 文件里面为空,等到 3s 过去后才会有值。
➜ intoC git:(master) ✗ ./rss sohu ➜ intoC git:(master) ✗ cat output.txt ➜ intoC git:(master) ✗ cat output.txt ➜ intoC git:(master) ✗ cat output.txt ➜ intoC git:(master) ✗ cat output.txt www.sohu.com
也就是说 rss 程序启动独立进程运行 rssgossip.py,而子进程一创建就会父进程没关系了,rssgossip.py 还没有完成任务,rss 就结束了,所以 output.txt 为空,也 就是说,操作系统必须提供一种方式,让你等待子进程完成任务。
1.5 waitpid() 函数
针对上面的问题, waitpid()
函数会让子进程运行结束后才返回。我们在程序的最后面加上下面的代码:
int pid_status; if (waitpid(cf, &pid_status, 0) == -1) { error("等待子进程时发生错误"); } return 0;
然后在运行程序:
➜ intoC git:(master) ✗ gcc rss.c -o rss ➜ intoC git:(master) ✗ ./rss sohu ➜ intoC git:(master) ✗ cat output.txt www.sohu.com
rss 程序不是立即就退出的,而是等一会,等待 rssgossip.py 完成后再退出。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: C 语言 系统调用 fork 函数
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论