fileno() 返回描述符号
每打开一个文件,操作系统都会在描述符表中新注册一项。假设你打开了某个文件:
FILE *my_file = fopen("guitar.mp3", "r");
操作系统会打开 guitar.mp3 文件,然后返回一个指向它的指针,操作系统还会遍历描述符表寻找空项,把新文件注册在其中。
那么如何根据文件指针知道它是几号描述符呢?答案是调用 fileno() 函数。
在失败时不返回-1 的函数很少,fileno() 就是其中之一。只要你把打开文件的指针传给 fileno() ,它就一定会返回描述符编号。
dup2() 复制数据流
每次打开文件都会使用描述符表中新的一项。但如果你想修改某个已经注册过的数据流,比如想让 3 号描述符重新指向其他数据流,该怎么做?可以用 dup2() 函数,dup2() 可以复制数据流。假设你在 4 号描述符中注册了 guitar.mp3 文件指针,下面这行代码就能同时把它连接到 3 号描述符:
虽然 guitar.mp3 文件只有一个,与它相连的数据流也只有一条,但数据流(即 FILE* )同时注册在了文件描述符 3 和 4 中。
既然你已经学会了如何在描述符表中查找文件和修改数据流,也就能把进程的标准输出重定向到某个文件。
还在为错误代码烦恼?
每次你在系统调用时都需要反反复复写那些错误处理代码。还犹豫什么!赶快使用我们的独家秘方,我们将向你展示如何重用错误代码,从此你将告别重复代码:
下面两段代码一看头就大:
有没有办法可以消除重复代码呢?当然有!只要创建一个 error() 函数,就可以一劳永逸。
error() 函数是什么?这些 return 怎么处理?总不见得也移到 error() 函数里吧?
不需要!exit() 系统调用是结束程序的最快方式。完全不用操心怎么返回主函数,直接调用 exit(),你的程序就会灰飞烟灭!
首先,需要把处理代码放到一个单独的 error() 函数中,然后把 return 语句换成 exit() 系统调用。
现在就可以把那些烦人的错误检查代码换成:pid_t pid = fork();if (pid == -1) { error("无法克隆进程");}if (execle(...) == -1) { error("无法运行脚本");}
这么做简单多了!
警告:每次程序执行只有一次调用 exit() 的机会,“程序突然结束恐惧症”患者慎用。
磨笔上阵
程序把 rssgossip.py 脚本的输出保存到 stories.txt 文件中。程序只搜索一个 RSS 源,其他都和 newshound 一样。程序少了一行把子进程的标准输出重定向到 stories.txt 的代码,你能补出来吗?你可能用到描述符表的知识。
磨笔上阵解答
程序把 rssgossip.py 脚本的输出保存到 stories.txt 文件中。程序只搜索一个 RSS 源,其他都和 newshound 一样。程序少了一行把子进程的标准输出重定向到 stories.txt 的代码,凭借对描述符表的了解,你把它补了出来。你写对了吗?程序把子进程(脚本程序)的描述符表改成了这样:也就是说当 rssgossip.py 把数据发往标准输出时,数据应该出现在 stories.txt 文件中。
#数据流 0 键盘 1stories.txt 文件 2 屏幕 3stories.txt 文件
试驾
编译运行程序,将看到:
发生了什么事?
当程序用 fopen() 打开 stories.txt 文件时,操作系统把文件 f 注册到了描述符表中,fileno(f) 是文件 f 使用的描述符编号,而 dup2() 函数设置了标准输出描述符(1 号),让它也指向了该文件。
脑力风暴
假设 RSS 源中的确有你要找的新闻,可为什么程序结束以后 stories.txt 还是空的?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论