Linux下 文件描述符(fd)与 文件指针(FILE*)
一、文件描述符(fd)
我们都知道在Linux下一切皆文件。当然设备也不例外,如果要对某个设备进行操作,就不得不打开此设备文件,打开文件就会获得该文件的文件描述符fd( file discriptor), 它就是一个很小的整数,每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。
图中文件描述符即为文件描述符数组的下标
文件描述符的分配规律:从当前未使用的最小的整数开始分配;
文件描述符的缺点:
不能移植到UNIX以外的系统上去,也不直观。
举一个系统函数的例子:ssize_t write ( int fd, const void *buf, size_t count);
write: 是系统写函数 fd: 文件描述符 (一个整数) *buf: 内容写在哪里 count: 一次写多少个;
概括:
每一个进程在PCB(Process Control Block)即进程控制块中都保存着一分文件描述符表,文件描述符就是这个表的索引,文件描述符表中每个表项都有一个指向已打开文件的指针。现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。
fd详解
fd:为打开文件的文件描述符,而每个进程都有一张文件描述符表,fd文件描述符就是这张表的索引,同样这张表中有一表项,该表项又是指向前面提到打开文件的file结构体,file结构体才是内核中用来描述文件属性的结构体。
FILE结构体
1、FILE结构体中的成员
缓冲区基址,缓冲区当前指针,缓冲区大小,缓冲区剩余字节数,文件读写方式等。
struct FILE
{
char *_ptr;//文件输入的下一个位置
int _cnt;//当前缓冲区的相对位置
char *_base;//指基础位置(文件的起始位置)
int _flag;//文件标志
int _file;//文件的有效性验证
int _charbuf;//检查缓冲区状况,如果缓冲区则不读取
int _bufsiz;//文件的大小
char *_tmpfname;//临时文件名
};
1
2
3
4
5
6
7
8
9
10
11
2、(FILE*)文件指针
文件指针指向进程用户区中一个被叫做FILE结构的结构数据。FILE结构包括一个缓冲区和一个文件描述符 。而文件描述符是文件描述符表的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。
通常,任何程序运行起来之后都会默认的打开三个标准输入流(stdin:键盘),标准输出流(stdout:显示器),标准错误流(stderr:显示器)。
文件描述符与文件指针的区别
简单归纳:fd只是一个整数,在open时产生,起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针file。
open:文件描述符的操作(如:open)返回的是一个文件描述符(int fd),内核会在每个进程空间中维护一个文件描述符表,所有打开的文件都将通过,此表中的文件描述符来引用。
fopen:流(如:fopen)返回的是一个文件指针(即指向FILE结构体的指针),FILE结构是包含有文件描述符的,fopen可以看做是open(fd直接操作的系统调用)的封装,它的优点是带有I/O缓存。
C语言的文件指针与文件描述符的相互转换可通过fdopen和fileno两个函数实现。它们都包含在头文件stdio.h中。
fdopen的原型:
FILE *fdopen(int filedes,const char *opentype);
1
第一个参数filedes是一个打开的文件描述符,opentype是表示打开方式的字符串,和fopen函数具有相同的取值,比如”w”或”w+”等。但是你必须保证该字符串的描述和文件实际的打开方式是匹配的。函数fopen()就是返回打开文件的指针;如果操作失败,返回空指针null。
把文件流指针转换成文件描述符用fileno函数,
其原型为:
int fileno(FILE *stream);
1
它返回的是和stream文件流对应的文件描述符。如果失败,返回-1;
当程序执行时,就已经有三个标准文件流打开了,它们分别是(标准输入)stdin,(标准输出)stdout,(标准错误输出)stderr,和流式文件相对应的是,也有三个文件描述符被预先占用(它们分别是:
0((标准输入)stdin),1((标准输出)stdout),2((标准错误输)stderr));