fd与FILE结构体的纵向对比

文件描述符(fd)
对于Linux而言,所有对设备(对于Linux而言,一切皆文件)和文件的操作都使用文件描述符来进行的。文件描述符是用来访问文件的。
文件描述符是一个非负的整数,是一个索引值,指向内核中每个进程打开文件的记录表。
当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符用于后续对文件的读写操作;当需要读文件时,也需要把文件描述符作为参数传递给相应的函数。
通常情况下,将一个程序从硬盘加载到内存后,这个程序就化身为了一个进程,这时系统会默认打开三个文件:标准输入(stdin)、标准输出(stdout)、标准错误(stderr)。
这三个文件相对应的三个文件描述符分别为0、1、2.所以后面如果创建新的文件,那么此时这个新文件的文件描述符就是3了。这是因为在Linux中,文件的描述符分配是从小到大逐个查询文件描述符是否已经使用,然后再分配。
相应的如果你提前关闭了文件描述符1,那么新建的文件描述符就是1。
这里写图片描述
一个进程的文件描述符与对应的文件的关系简图:
这里写图片描述

FILE结构体
C语言的stdio.h头文件中,定义了用于文件操作的结构体FILE。这样,我们通过fopen返回一个文件指针(指向FILE结构体的指针)来进行文件操作。
FILE结构体中最重要的两个成员变量是:
文件描述符和缓冲区的大小

//C语言文件指针域文件描述符之间可以相互转换
int fileno(FILE* stream)
FILE* fdopen(int fd,const char* mode)
struct _iobuf
{
    char* _ptr; //缓冲区当前指针
    int _cnt;
    char* _base;//缓冲区基址
    int _flag;//文件读写模式
    int _file;//文件描述符
    int _charbuf;//缓冲区剩余自己个数
    int _bufsiz;//缓冲区大小
    char* _tmpfname;
}
typedef struct _iobuf FILE;

FILE结构体与文件描述符之间的关系:
这里写图片描述
对上图内容的简要介绍:
1.进程打开一个文件的过程:
进程通过系统调用open()来打开一个文件,实质上是获得一个文件描述符,以便于进程通过文件描述符来读写该文件、进程打开文件时,会为该文件创建一个file对象,并将一个指向该file对象的指针存入进程描述符表(进程描述符数组),进而确定了打开文件的文件描述符(数组下标)。
open()系统调用是在内核里通过sys_open()实现的;sys_open()将创建文件的dentry、inode和file对象。
创建file对象时,将file对象f_op指向了所属文件系统的操作函数集file_operations,而该函数集又来自具体文件的i节点,于是虚拟文件系统就与实际文件系统的操作衔接起来了。
并在file_struct结构体的进程打开文件表fd_array[NR_OPEN_DEFAULT]中查找一个空闲表项(也就是此时数组中最小的未被占用的表项),然后返回该表项的下标(文件描述符)。
2.
描述符数组存放在进程打开的文件表files_struct结构体中。
文件描述符数组中存放了一个进程所打开的所有文件
3.file_struct结构体定义:

struct files_struct { atomic_t count; /* 共享该表的进程数 */
rwlock_t file_lock; /* 保护以下的所有域,以免在tsk->alloc_lock中的嵌套*/
int max_fds; /*当前文件对象的最大数*/
int max_fdset;/*当前文件描述符的最大数*/
int next_fd; /*已分配的文件描述符加1*/
struct file ** fd; /* 指向文件描述符数组的指针 */
fd_set *close_on_exec; /*指向执行exec( )时需要关闭的文件描述符*/
fd_set *open_fds; /*指向打开文件描述符的指针*/
fd_set close_on_exec_init;/* 执行exec( )时需要关闭的文件描述符的初 值集合*/
fd_set open_fds_init; /*文件描述符的初值集合*/
struct file * fd_array[32];/* 文件对象指针的初始化数组*/};

4.file结构体:

struct file
{
struct list_head f_list; /*所有打开的文件形成一个链表*/
struct dentry *f_dentry; /*指向相关目录项的指针*/
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驱动程序所需 */
};

5.file结构体的几个重要的成员变量:
f_flags:表示打开文件的权限
f_pos:表示当前读写文件的位置
f_count:表示打开文件的引用计数,如果有多个文件指针指向他,就会增加f_count的值
f_mode:设置对文件的访问模式,例如:只读、只写、可读可写等

6.小结:
file_struct是操作系统用来管理文件的数据结构,当我们创建一个进程时,会创建文件描述符,进程控制块PCB中的fs指针指向文件描述符表,当我们创建文件时,会为指向该文件的指针FILE*关联一个文件描述符并添加在文件描述符表中。在文件描述符表中fd相当于数组的索引,FILE*相当于数组的内容,指向一个文件结构体。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值