所有执行I/O操作的系统调用都以文件描述符,即一个非负整数来指代所打开的文件。文件描述符可以用来表示所有类型的已打开文件。同时,多个文件描述符可以指向同一个打开文件,因为有在不同进程中打开同一个文件的需求。

那么,系统是如何维护硬盘文件与文件描述符之间的联系呢?

要理解具体的情况如何,需要查看由内核维护的3个数据结构:

  • 进程级的文件描述符
  • 系统级的打开文件表
  • 文件系统的i-node表
针对每个进程,内核为其维护打开文件的描述符(open file descriptor)表。该表的每一项都记录了单个文件描述符的相关信息,如下所示:
  • 控制文件描述符操作的一组标志(目前仅定义了一个,即close-on-exec标志)
  • 对打开文件句柄的引用
内核对所有打开的文件维护一个系统级的描述表格(open file description table)。也叫打开文件表(open file table),表中的每一项称为打开文件句柄(open file handle)。一个打开文件句柄存储了与一个打开文件相关的全信息,如下:
  • 当前文件偏移量(调用read()和write()时更新,或使用lseek()直接修改)
  • 文件的访问模式(如调用read()时设置的只读模式、只写模式等)
  • 与信号驱动I/O相关的设置
  • 对该文件i-node对象的引用
同时,文件系统又会对每个存储其上的文件建立一个i-node表。这里只给出i-node表的信息:
  • 文件类型(如常规文件、套接字或FIFO)和访问权限
  • 一个指针,指向该文件所持有的的锁的列表
  • 文件的各种属性,包括文件大小以及不同类型操作相关的时间戳
下图展示了这3个数据结构之间的关系。在下图中,两个进程拥有诸多打开 的文件描述符:
在进程A中,文件描述符1和20都指向同一个打开的文件句柄23,这可能是通过调用dup、dup2或fcntl形成的。
进程A的文件描述符2和进程B的文件描述符2都指向同一个打开的文件句柄73,这可能是调用fork之后出现的。或者某进程通过UNIX域套接字将一个打开的文件描述符传递给另一个进程。
此外,进程A的文件描述符0和进程B的文件描述符3分别指向不同的打开文件句柄,但这些打开文件句柄指向同一个i-node表中的相同条目。可能是两个进程各自对同一个文件调用open打开。同时,在一个进程中两次打开同一个文件,也会出现这种情况。
这里我们可以得到一些结论:
  1. 两个不同的文件描述符,若指向同一个文件打开句柄,将共享同一文件的偏移量。因此,如果通过其中一个文件描述符来修改文件偏移量(调用open、write、lseek),那么从另一个文件描述符中也会得到相应的改变。不管这两个文件描述符是分别属于同一进程还是不同的进程;
  2. 要获取和修改打开的文件标志(如O_APPEND、O_NONBLOCK等),可以执行fcntl()的F_GETFL和F_SETFL操作,其对作用域的约束与上一条类似;
  3. 相比之下,文件描述符标志(close-on-exec标志)为进程和文件描述符所私有,对这一标志的修改将不会影响同一进程或不同进程中的其他文件描述符。
下面给出具体的实例验证上面的讨论。
fd1=open(file,O_CREAT | O_RDWR | O_TRUNC,S_IRUSR | S_IWUSR);
fd2=dup(fd1);
fd3=open(file,O_RDWR);
write(fd1,"hello",6);
write(fd2,"world",6);
lseek(fd2,0,SEEK_SET);
write(fd1,"HELLO",6);
write(fd3,"yellow",6);

上面的代码中有三个文件描述符,都是打开同一个文件,即共享同一个i-node项。不同的是fd2通过调用dup复制文件描述符fd1,因此fd1与fd2共享同一个文件打开句柄。fd3是同一个进程中另一个open操作,因此和fd1对比,两个文件描述符指向不同的文件打开句柄,但指向同一个i-node项目。下图展示了它们的关系:

因此,对fd1和fd2的open、write、lseek等操作会使文件偏移量发生改变。fd1写入“hello”之后,文件偏移量变为6,fd2写入时在6之后写入,此时文件中的内容是“helloworld”;

当fd2调用lseek改变文件偏移量为0,之后fd1写入文件,是在偏移量为0的基础上写入,因此覆盖最初的6字节,文件内容变为“HELLOworld”;对于fd3,因为与fd1和fd2指向不同的文件打开句柄,因此fd1和fd2的操作不影响fd3指向的文件打开句柄的文件偏移量,所以fd3写入时会覆盖最初的6字节,此时文件内容变为“yelloworld”。

程序运行结果如下:

结果证实了我们的讨论。

文件描述符与打开文件的关系相关推荐

  1. Linux下多个进程可以同时打开同一个文件吗?文件描述符与打开文件的关系?

    一:结论 1.两个进程中分别产生生成两个独立的fd 2.两个进程可以任意对文件进行读写操作,操作系统并不保证写的原子性 3.进程可以通过系统调用对文件加锁,从而实现对文件内容的保护 4.任何一个进程删 ...

  2. Linux中的文件描述符与打开文件之间的关系

    1. 概述 在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件.目录文件.链接文件和设备文件.文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其是 ...

  3. linux c中的文件描述符与打开文件之间的关系

    转载请说明出处:http://blog.csdn.net/cywosp/article/details/38965239 1. 概述     在Linux系统中一切皆可以看成是文件,文件又可分为:普通 ...

  4. linux文件描述符与标识符,文件描述符fd

    这里以问答的方式来讨论这个问题: 1. 文件描述符 fd 和文件指针 FILE *的关系? 文件描述符是什么?我们知道每一个进程都有一个自己的PCB(进程控制块),进程控制块的结构是: struct ...

  5. 文件描述符fd和文件指针File* fp的区别和转换

    在linux系统中把设备和普通文件也都看做是文件,要对文件进行操作就必须先打开文件,打开文件后会得到一个文件描述符,它是一个很小的正整数,是一个索引值.  内核会为每一个运行中的进程在进程控制块pcb ...

  6. 《Python Cookbook 3rd》笔记(5.18):将文件描述符包装成文件对象

    将文件描述符包装成文件对象 问题 你有一个对应于操作系统上一个已打开的 I/O 通道 (比如文件.管道.套接字等)的整型文件描述符,你想将它包装成一个更高层的 Python 文件对象. 解法 一个文件 ...

  7. linux 文件指针,Linux中文件描述符fd与文件指针FILE*互相转换实例解析

    本文研究的主要是Linux中文件描述符fd与文件指针FILE*互相转换的相关内容,具体介绍如下. 1.文件描述符fd的定义:文件描述符在形式上是一个非负整数.实际上,它是一个索引值,指向内核为每一个进 ...

  8. java jai create 方法_Java-JAI创建似乎使文件描述符保持打开状态

    我有一些旧代码,直到最近仍在工作,但是现在看来已经讨厌了,因为它可以在使用OpenJDK 6而不是Java SE 6的新服务器上运行. 这个问题似乎与JAI.create有关.我有jpeg文件,可以缩 ...

  9. linux中文件描述符fd和文件指针flip的理解

    整理自:http://www.cnblogs.com/Jezze/archive/2011/12/23/2299861.html 简单归纳:fd(file descriptor)只是一个整数,在ope ...

最新文章

  1. 每日一皮:这张图送给正在努力改Bug的你
  2. html 中加号的表示方法,CSS的+(加号)选择器怎么用
  3. Bootstrap3代码模板
  4. 小米9来袭 雷军微博疯狂暗示:有望MWC亮相?
  5. 4月第三周国内域名解析商Top10:万网升至20.32%
  6. Atitit q2016 q5 doc list on home ntpc.docx
  7. it人才计算机知识题,Excel试题_电脑基础知识_IT/计算机_专业资料
  8. 致远项目管理SPM系统五大技术平台层-CMP能力概述
  9. 阿里P4 - P14技能要求及对应薪资曝光
  10. java项目账户充值提现_资金充值提现明细
  11. Java 运算符(Operators)
  12. SAS实验2——假设检验
  13. 手机就能申请摇号 杭州市小客车摇号功能全新上线
  14. 暾盛机器人_移动机器人视觉伺服.pdf
  15. java免费获取物流信息
  16. 食物链 (种类并查集)
  17. 如何二叉树里面查找一个数
  18. spring容器destory时没有调用destory-method解决方法
  19. allennlp与pytorch版本匹配
  20. 《神经科学:探索脑》学习笔记(第13章 运动的脊髓控制)

热门文章

  1. java sundry tips
  2. hdu2115: I Love This Game
  3. 2010.07.13_19:30
  4. 服务器建网站www无法访问,IIS6服务器搭建网站无法访问解决方案总结_DOIT.com.cn...
  5. finditerable 转list_java – 通过拆分和运行将ListenableFuture转换为Iterable
  6. 按小时分组mysql 补齐_分组记录按小时或按天白天和mysql的
  7. mysql alter怎么用,mysql alter话语用法
  8. python 编辑excel需要什么包_Python 中操作EXCEL表格的包
  9. java 二进制 归属权限_【Java EE 学习 75 上】【数据采集系统第七天】【二进制运算实现权限管理】【权限分析和设计】...
  10. dataframe转化为array_【Python专栏】12 种高效 Numpy 和 Pandas 函数为你加速分析