这周末开始看《APUE》,和《linux内核设计与实现》、《深入理解linux内核》同步往前推进。
图1-4代码中用到了
while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
if (write(STDOUT_FILENO, buf, n) != n)
err_sys("write error");
书中描述为:两个常量STDIN_FILENO和STDOUT_FILENO定义在<unistd.h>头文件中,它们指定了标准输入和标准输出的文件描述符。
刚开始误解为:只要在read和write的参数中传入这两个描述符,那么就不再是文件IO(低级IO)了,而改为标准IO(高级IO)了。
其实不是酱紫,而是:
只要调用的是read()write()函数,那就一定是文件IO操作。
而标准IO操作对应的则是stdin,stdout,stderr。
这里说的“标准”IO,与上面说的“指定了标准输入和标准输出的文件描述符”的“标准”二字概念不一样。
下面总结一下二者区别,五个区别对比参考:
I (stdin,stdout,stderr):
- stdin等是FILE *类型;是C中的标准输入输出流,缓冲方式进行。
- 属于标准I/O(是C语言标准输入输出流),是文件流方式。属于高级I/O,带缓冲;
- 在<stdio.h>。
- 使用stdin等的函数主要有:fread、fwrite、fclose等标准库调用,基本上都以f开头。
- stdin等由用户层的标准C库实现;提供的文件操作函数库都是用FILE*来表示文件,stdin等就是指向标准输入设备文件的FILE*。
II (STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO):
- STDIN_FILENO等是int类型;是文件描述符,一般定义为0, 1,2;
- 属于系统API接口库(是linux OS文件读写描述符);没有buffer的I/O,直接调用系统调用。属于低级IO,要自己处理缓冲。
- 在<unistd.h>。
- 使用STDIN_FILENO等的函数有:read、write、close等
- STDIN_FILENO等用于系统层的系统调用,操作系统级提供的文件API都是以文件描述符来表示文件。STDIN_FILENO就是标准输入设备(一般是键盘)的文件描述符。
III (二者的联系):
标准库内封装了系统 API 调用,如 fread 内部实现调用 read。
例如:
printf的调用流程
printf -> stdout -> STDOUT_FILENO(1) -> 终端(tty)
【通常守护进程在后台运行,所以要将它的标准输入输出重定向到/dev/null】
在linux下,stdin等的实现必然依赖于文件描述符。
也就是说这两个东西在不同的层次,一个是用户层的C库,一个是系统层的系统调用。
程序启动时:
FILE * stdin / stdout / stderr 对应的文件描述符(fd)分别是 STDIN_FILENO(0) / STDOUT_FILENO(1) / STDERR_FILENO(2) 。
但是,可以通过FILE *freopen(const char *path, const char *mode, FILE *stream); 来改变,使文件描述符(fd)对应到其他的stream上。
(对于“流”的理解,以后写文)
参考:http://bbs.csdn.net/topics/240009889