博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux-文件描述符的本质及与文件指针的区别
阅读量:5245 次
发布时间:2019-06-14

本文共 2370 字,大约阅读时间需要 7 分钟。

文章参考:、、

推荐:

系统中文件相关表

  右侧的表称为i节点表,在整个系统中只有1张。该表可以视为结构体数组,该数组的一个元素对应于一个物理文件。

  中间的表称为文件表,在整个系统中只有1张。该表可以视为结构体数组,一个结构体中有很多字段,其中有3个字段比较重要:

    file status flags:用于记录文件被打开来读的,还是写的。其实记录的就是open调用中用户指定的第2个参数

    current file offset:用于记录文件的当前读写位置(指针)。正是由于此字段的存在,使得一个文件被打开并读取后,下一次读取将从上一次读取的字符后开始读取
    v-node ptr:该字段是指针,指向右侧表的一个元素,从而关联了物理文件。

  左侧的表称为文件描述符表,每个进程有且仅有1张。该表可以视为指针数组,数组的元素指向文件表的一个元素。最重要的是:数组元素的下标就是大名鼎鼎的文件描述符,数组元素的值就是指向 File 结构体的指针

 

系统调用时的操作

  文件描述符的操作函数 open, 返回一个文件描述符,内核会在每个进程空间中维护一个文件描述符表,所有打开的文件都将通过此表中的文件描述符来引用。

    新建一个i节点表元素,让其对应打开的物理文件(如果对应于该物理文件的i节点元素已经建立,就不做任何操作);

    新建一个文件表的元素,根据open的第2个参数设置file status flags字段,将current file offset字段置0,将v-node ptr指向刚建立的i节点表元素;

    在文件描述符表中,寻找1个尚未使用的元素,在该元素中填入一个指针值,让其指向刚建立的文件表元素。最重要的是:将该元素的下标作为open的返回值返回。

  文件描述符的操作函数 read(write,)根据传入的文件描述符,OS就可以找到对应的文件描述符表元素,进而找到文件表的元素,进而找到i节点表元素,从而完成对物理文件的读写。

  而流操作函数 fopen, 返回的是一个FILE结构指针,FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装,它的优点是带有I/O缓存。

 

文件描述符和文件指针的概念一总

  文件描述符:在linux系统中打开文件就会获得文件描述符,它是个很小的正整数。每个进程在PCB(Process Control Block)中保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针。即已打开的文件在内核中用 File 结构体表示,文件描述符表中的指针指向 File 结构体优点是兼容POSIX标准,许多系统调用都依赖于它;缺点是不能移植到unix之外的系统上去

  文件指针:C语言中使用文件指针而不是文件描述符做为I/O的句柄。文件指针指向进程用户区中的一个被称为FILE结构的数据结构。FILE结构主要包括一个I/O缓冲区和一个文件描述符。而文件描述符是文件描述符表中的一个索引,因此从某种意义上说文件指针就是句柄的句柄(在Windows系统上,文件描述符被称作文件句柄)。相当于在上图中最左侧又虚拟出一个 struct File,其中 struct 中有个元素是文件描述符,指向进程表项中的 fd 索引(自己的理解,不知道正不正确)。文件指针的优点是C语言中的通用格式,便于移植。

  既然FILE结构中含有文件描述符,那么可以使用fopen来获得文件指针,然后从文件指针获取文件描述符,文件描述符应该是唯一的,而文件指针却不是唯一的,但指向的对象是唯一的

 

进程与文件描述符

  内核会在每个进程空间中维护一个文件描述符表, 所有打开的文件都将通过此表中的文件描述符来引用; 而流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O 缓存。

  每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用 FILE 结构体表示,文件描述符表中的指针指向 FILE 结构体

 

fork 对文件描述符的影响

  fork会导致子进程继承父进程打开的文件描述符,其本质是将父进程的整个文件描述符表复制一份,放到子进程的PCB中。因此父、子进程中相同文件描述符(文件描述符为整数)指向的是同一个文件表元素,这将导致父(子)进程读取文件后,子(父)进程将读取同一文件的后续内容。所以在创建守护进程时,都使用 close 关闭掉从父进程继承的文件描述符

 

FILE的结构

struct _iobuf {  char *_ptr; //缓冲区当前指针  int _cnt; //文件的引用计数  char *_base; //缓冲区基址  int _flag; //文件读写模式  int _file; //文件描述符  int _charbuf; //缓冲区剩余自己个数  int _bufsiz; //缓冲区大小  char *_tmpfname;};typedef struct _iobuf FILE;

 

open和fopen的区别

  open:返回一个文件描述符,无缓冲,与 write、read 配合使用

  fopen:返回 File *,有缓冲,与 fwrite、fread 配合使用

 

转载于:https://www.cnblogs.com/JohnABC/p/7227379.html

你可能感兴趣的文章
tarjan(缩点)
查看>>
Lombok插件
查看>>
Linux上安装Libssh2
查看>>
自定义EL函数
查看>>
stm32的电源
查看>>
splice的多种用法
查看>>
20162304 2017-2018-1 《程序设计与数据结构》第二周学习总结
查看>>
九.python面向对象(双下方法内置方法)
查看>>
2018-09-12
查看>>
go:channel(未完)
查看>>
[JS]递归对象或数组
查看>>
CSS与Theme的作用——Asp.Net
查看>>
LeetCode(17) - Letter Combinations of a Phone Number
查看>>
20165115 2017-2018-2 《Java程序设计》第四周学习总结
查看>>
Linux查找命令对比(find、locate、whereis、which、type、grep)
查看>>
WPF自定义集合控件概述与遇到的问题
查看>>
路由器外接硬盘做nas可行吗?
查看>>
python:从迭代器,到生成器,再到协程的示例代码
查看>>
pytest的参数化测试
查看>>
Java多线程系列——原子类的实现(CAS算法)
查看>>