Linux-文件描述符

相关系统调用接口

我们在学习c语言时,在学习i/o操作时,用到的相关c接口:fopen,fclose,fread,fwrite等等,我们都称之为c库函数。
不止c语言有这些接口,其他语言也有,但是实际上不管是哪种语言,最终他们都会采用系统调用的方式来进行文件访问。
下面,介绍与i/o相关的系统调用。

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);
close
       #include <unistd.h>

       int close(int fd);
read
       #include <unistd.h>

       ssize_t read(int fd, void *buf, size_t count);
write
       #include <unistd.h>

       ssize_t write(int fd, const void *buf, size_t count);

以上系统调用用法在man手册都可查看到。不再赘述。

下面解释以下系统调用与库函数的关系:
在下面这张图我们可以看到操作系统在底层软硬件的分层结构,同时观察到lib库函数所在与系统调用的关系,显然他们是上下级的关系,lib是对系统调用的二次封装,方便二次开发。
这里写图片描述

文件描述符

我们从刚刚上述系统调用函数原型中可以看到,四个函数都需要一个参数fd(open函数fd是返回值),那么fd究竟是什么呢。
这个fd就是文件描述符。
看下面这个例子:

int main()
{
    int fd=open("txt",O_RDONLY);
    printf("%d\n",fd);
    return 0;
}

结果如下:
这里写图片描述
通过man手册我们知道man函数的返回值是新打开文件的文件描述符。如果失败,返回-1.
但是为什么是3呢?如果函数调用失败返回值是-1,那么说明文件描述符一定不是个负数,却是从3开始,那么0,1,2是否是被占用了呢?
答案是是的。
原因:Linux下进程默认情况下会有3个缺省打开的文件描述符,分别是

  • 0:stdin
  • 1:stdout
  • 2:stderror

所以现在我们对文件描述符也仅仅只是认为他是个从0开始小整数。
我们可以思考一个问题,进程在操作系统是如何描述及管理的,第一反应当然是PCB,PCB中存储了进程相关的一系列信息。
实际上,在我们打开文件时,操作系统在内存中要也创建相应的数据结构来描述文件。于是就有了file结构体,表示此时打开的文件对象。
当进程执行open系统调用,就必须让进程和文件联系起来。进程是如何找得到所要打开的文件的?因为 每个进程都有一个指针 ,该指针指向一张表,这张表包含一个指针数组,在这个指针数组中的每个元素都是一个指向打开文件的指针。
所以,本质上,文件描述符就是该文件指针数组的下标
这里写图片描述

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

FILE

因为i/o相关函数与系统调用接口对应,并且库函数封装系统调用,所以本质上,访问文件还是通过fd访问的。
所以再FILE这个结构体里,必然封装了fd。

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

struct _IO_FILE {
247   int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
248 #define _IO_file_flags _flags
249 
250   /* The following pointers correspond to the C++ streambuf protocol. */
251   /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
252   char* _IO_read_ptr;   /* Current read pointer */
253   char* _IO_read_end;   /* End of get area. */
254   char* _IO_read_base;  /* Start of putback+get area. */
255   char* _IO_write_base; /* Start of put area. */
256   char* _IO_write_ptr;  /* Current put pointer. */
257   char* _IO_write_end;  /* End of put area. */
258   char* _IO_buf_base;   /* Start of reserve area. */
259   char* _IO_buf_end;    /* End of reserve area. */
260   /* The following fields are used to support backing up and undo. */
261   char *_IO_save_base; /* Pointer to start of non-current get area. */
262   char *_IO_backup_base;  /* Pointer to first valid character of backup area */
263   char *_IO_save_end; /* Pointer to end of non-current get area. */
264 
265   struct _IO_marker *_markers;
266 
267   struct _IO_FILE *_chain;
268 
269   int _fileno;//封装的文件描述符
270 #if 0
271   int _blksize;
272 #else
273   int _flags2;
274 #endif
275   _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */
276 
277 #define __HAVE_COLUMN /* temporary */
278   /* 1+column number of pbase(); 0 is unknown. */
279   unsigned short _cur_column;
280   signed char _vtable_offset;
281   char _shortbuf[1];
282 
283   /*  char* _save_gptr;  char* _save_egptr; */
284 
285   _IO_lock_t *_lock;
286 #ifdef _IO_USE_OLD_IO_FILE
287 };

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值