今日阅读《UNIX环境高级编程2》才发现一些以前从未注意过的细节。
linux编程使用的open、close、read、write等文件IO函数属于系统调用的,其实现方式是用了fctrl、ioctrl等一些底层操作的函数。而标准IO库中提供的是fopen、fclose、fread、fwrite等面向流对象的IO函数,这些函数在实现时本身就要调用linux的文件IO这些系统调用。
在应用上,文件读写时二者并没区别,但是一些特殊文件,如管道等,只能使用文件IO操作。文件IO的一个方便之处在于,对于一切linux中的文件对象,都可以操作,这也是linux把系统中所有资源,都映射成文件节点的优越之处。另一方面,在一些应用中,如果需要格式化字符串输入输出时,标准IO提供了一个很好的接口,fprintf(FILE* fp, char *platestr,...),而在文件IO中没有这样的函数,那么如果我们按照习惯用open函数打开了文件,获得文件描述符fd,只要根据fd得到对应的标准IO流的指针fp,就可以使用fprintf函数做格式化输出了。
实现这个功能的函数就是 fdopen
标准IO提供了3个打开文件流的函数
- #include <stdio.h>
- FILE *fopen(const char *restrict pathname, counstchar *restrict type);
- FILE *freopen(const char *restrict pathname, counst char *restrict type,
- FILE *restrict fp );
- FILE *fdopen(int filedes, counst char *restrict type);
- 三个函数成功返回文件指针,出错返回NULL
其中fopen是最长用的函数。
freopen的左右是在参数指定的流上打开一个文件,若文件已经打开则先关闭该流;若文件流已经定向,则清楚定向。此函数可以用于把指定的文件打开成为标准输入输出。
fdopen的作用是从现有的文件描述符(从open、dup、fctrl、pipe、socket、accept等处获得)打开一个流使其与该文件描述符相关联。利用这个函数就可以实现前面所说的对于一般的文件IO做格式化输入输出等标准IO的操作。
需要注意的是,前两个函数属于ISO C的标准,fdopen属于POSIX.1的标准。ISO C 的标准中没有文件描述符的概念。另外,fdopen的第二个参数与fopen的参数类似:
r/rb
w/wb
a/ab
r+ /r+b/rb+
w+/w+b/wb+
a+/a+b/ab+
区别是fdopen的参数中如果是二进制文件,需要指定b参数,因为ISO C中是要区别二进制文件和文本文件的的,而在linux内核中对二者没有不同的待遇。另外,由于fdopen打开的文件是已经打开过的,因此w参数并不会把文件长度截断为0,是否截断取决于open参数中的O_TRUNC参数。所以每次fwrite写入的数据都将写入文件尾。
以上就是从文件符获得文件IO流指针的方法。若我们先得到了文件IO流指针,再需要获得文件描述符,怎么办呢?因为所有的标准IO的函数最终都要调用linux提供的文件IO这类系统调用,所以每个标准IO流都必然关联一个文件描述符,用这个函数就可以得到关联的文件描述符了
int fileno( FILE *fp);
返回值:与该流关联的文件描述符