文件描述符

本文介绍了Linux系统中文件描述符(fd)的概念及其作用,并详细解释了open函数的工作原理。文章探讨了fd作为小整数的特性,以及它是如何与进程和文件建立联系的。此外,还介绍了file结构体的作用,以及文件描述符的分配规则。

在认识返回值之前,先来认识两个概念:

库函数(libc):c标准库当中的函数,如fopen,fclose,fread,fwrite等。

系统调用接口:系统提供的接口,如open,close,read,write等。

下图是有关操作系统概念的一张图:


从这张图中,我们可以看出,库函数和系统调用接口是上下级的关系。可以认为,lib是对系统调用的二次封装,方便二次开发。

我们再来看一下open函数的相关知识:

       #include <sys/types.h>
       #include <sys/stat.h>
       #include <fcntl.h>

       int open(const char *pathname, int flags);
       int open(const char *pathname, int flags, mode_t mode);

从上面这个函数我们可以看出,函数需要一个参数fd(open函数fd是返回值),这个fd就是文件描述符。

Linux进程默认情况下会有三个缺省打开的文件描述符,分别是标准输入(stdin)0,标准输出(stdout)1,标准错误(stderror)2。

0,1,2对应的物理设备一般是:键盘,显示器,显示器。

因此,我们现在对文件描述符可以认识为它是一个从0开始的小整数。

我们可以思考一个问题,进程在操作系统是如何描述及管理的,第一反应当然是PCB,PCB中存储了进程相关的一系列信息。

实际上,在我们打开文件时,操作系统在内存中要也创建相应的数据结构来描述文件。于是就有了file结构体,表示此时打开的

文件对象。 

当进程执行open系统调用,就必须让进程和文件联系起来。进程是如何找得到所要打开的文件的?因为 每个进程都有一个指

针,该指针指向一张表,这张表包含一个指针数组,在这个指针数组中的每个元素都是一个指向打开文件的指针。 

所以,本质上,文件描述符就是该文件指针数组的下标

文件描述符的分配规则:在files_struct数组中,找到当前没有被使用的最小的一个下标,作为新的文件描述符


FILE

因为i/o相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件还是通过fd访问的。 

所以在FILE这个结构体里,必然封装了fd。

我们在系统中找到这段源码查看一下是否封装了:

struct _IO_FILE {
 int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
 #define _IO_file_flags _flags
 
   /* The following pointers correspond to the C++ streambuf protocol. */
   /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
   char* _IO_read_ptr;   /* Current read pointer */
   char* _IO_read_end;   /* End of get area. */
   char* _IO_read_base;  /* Start of putback+get area. */
   char* _IO_write_base; /* Start of put area. */
   char* _IO_write_ptr;  /* Current put pointer. */
   char* _IO_write_end;  /* End of put area. */
   char* _IO_buf_base;   /* Start of reserve area. */
   char* _IO_buf_end;    /* End of reserve area. */
   /* The following fields are used to support backing up and undo. */
   char *_IO_save_base; /* Pointer to start of non-current get area. */
   char *_IO_backup_base;  /* Pointer to first valid character of backup area */
   char *_IO_save_end; /* Pointer to end of non-current get area. */
 
   struct _IO_marker *_markers;
 
   struct _IO_FILE *_chain;
 
   int _fileno;//封装的文件描述符
 #if 0
   int _blksize;
 #else
   int _flags2;
 #endif
   _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
 
 #define __HAVE_COLUMN /* temporary */
   /* 1+column number of pbase(); 0 is unknown. */
   unsigned short _cur_column;
   signed char _vtable_offset;
   char _shortbuf[1];
 
   /*  char* _save_gptr;  char* _save_egptr; */
 
   _IO_lock_t *_lock;
 #ifdef _IO_USE_OLD_IO_FILE
 };



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值