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 键盘 1 stories.txt文件 2 屏幕 3 stories.txt文件
试驾
编译运行程序,将看到:
发生了什么事?
当程序用fopen()
打开stories.txt文件时,操作系统把文件f
注册到了描述符表中,fileno(f)
是文件f
使用的描述符编号,而dup2()
函数设置了标准输出描述符(1号),让它也指向了该文件。
脑力风暴
假设RSS源中的确有你要找的新闻,可为什么程序结束以后stories.txt还是空的?