一张表图:
这张图描述的是进程级别的文件描述符和系统级别的打开文件表和系统级别的文件系统索引结点的连系关系。
由图可以知道:
- 每个进程维护的文件描述符表文件描述符从零开始, 进程间的文件描述符编号会重复;
- 打开文件表中的打开文件句柄可以对应同一个进程的多个文件描述符(dup dup2 fcntl效果),或者是不同进程间的多个文件描述符(例如父子进程的继承关系);
- 不同的打开文件表的打开文件句柄可能对应着同一个实体文件,可能是多次打开的效果。
文件描述符:
文件描述符是为了高效管理已经被打开的文件的所有i/o操作的系统调用所创建的索引,通常为大于等于0的整数。
操作系统为每个进程维护一个文件描述符表,表内的值都是从0开始递增,每个文件描述符对应一个打开的文件。所以不同的文件描述符可能对应同一个打开的文件,相同的描述符可能对应着不同的文件。
打开文件表
操作系统为在系统中打开的所有文件使用一个叫做打开文件表 的结构进行维护,表格中的每条记录称为打开文件句柄 。文件句柄记录了打开的文件的所有相关信息。
结构结点的信息:
struct file
{
struct list_head f_list; /*所有打开的文件形成一个链表*/
struct dentry *f_dentry;
/*指向相关目录项的指针(对象结点包含一个指向inode结点的对象指针)*/
struct vfsmount *f_vfsmnt; /*指向VFS安装点的指针*/
struct file_operations *f_op; /*指向文件操作表的指针*/
mode_t f_mode; /*文件的打开模式*/
loff_t f_pos; /*文件的当前位置*/
unsigned short f_flags; /*打开文件时所指定的标志*/
unsigned short f_count; /*使用该结构的进程数(引用计数)*/
unsigned long f_reada, f_ramax, f_raend, f_ralen, f_rawin;
/*预读标志、要预读的最多页面数、上次预读后的文件指针、预读的字节数以及预读的页面数*/
int f_owner; /* 通过信号进行异步I/O数据的传送*/
unsigned int f_uid, f_gid; /*用户的UID和GID*/
int f_error; /*网络写操作的错误码*/
unsigned long f_version; /*版本号*/
void *private_data; /* tty驱动程序所需 */
};
文件系统索引结点
index node (inode结点)
见:http://blog.csdn.net/danneel/article/details/47067301
由于文件索引有硬链接和软连接之分,所以,不同的打开文件句柄可能指向的是同一个物理文件。
dup
int dup(int oldfd);
系统将自动使用未被使用的最小文件描述符作为从定向的目标句柄,oldfd是重定向的源句柄。
dup2
int dup2(int oldfd, int newfd);
指定一个新的文件描述符newfd作为从定向的目标句柄, 如果newfd早已经被打开, 则将其挂关闭;如果两者相同,不关闭,返回newfd。
fcntl
fcntl函数针对文件描述符提供控制, 它的功能有以下几种:
1. 复制一个现有的描述符(cmd=F_DUPFD).
2. 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
3. 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
4. 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
5. 获得/设置记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW).
其中功能1 实现的功能与dup dup2相似, 只是形式不一样:
dup(oldfd);
~
fcntl(oldfd, F_DUPFD, 0);
dup2(oldfd, newfd);
~
fcntl(oldfd, F_DUPFD, newfd);
all