如何通过文件I/O函数操纵文件?
对于内核而言,所有打开的文件都通过文件描述符引用。文件描述符是一个非负整数。当打开一个现有文件或创建一个新文件时,内核向进程返回一个文件描述符。当读、些一个文件时,使用open或creat返回的文件描述符标识该文件,将其作为参数传送给read或write。另外可以通过lseek函数调整读或写的位置。当不想使用时,可以使用close函数关闭。关于每个函数的具体的使用请参考man 文档。
熟练使用以上函数可以很好的处理的文件。那是不是就结束了呢?思考以下问题
- 多个进程可以同时打开同一个文件吗?此时他们的文件描述符是不是一样的?每个进程对文件进行读写的时候其他进程可以感知到吗?可以同时在同一个位置写入数据吗?将文件描述符发送给其他进程是不是可以共享文件描述符?
- 同一个进程是否可以用不同数值的文件描述符操作同一个文件?
- 为什么文件可以重定向?重定向的原理?
内核用于所有I/O的数据结构
想要知道上面问题的答案,需要先介绍内核用于所有I/O的数据结构。
内核使用3种数据结构表示打开文件,它们之间的关系决定了文件共享方面一个进程对另一个进程可能产生的影响。
- (1)每个进程在进程表中都有一个记录项,记录项中包含一张打开文件描述符表,可将其视为一个矢量,每个描述符占用一项。与每个文件描述符相关联的是:
- 文件描述符标志(close_on_exec);
- 指向一个文件表项的指针。
- (2)内核为所有打开文件维持一张文件表。每个文件表项包含:
- 文件状态标志(读、写、添写、同步和非阻塞等);
- 当前文件偏移量;
- 指向该文件v节点表项的指针。
- (3)每个打开文件(或设备)都有一个v节点(v-node)结构。v节点包含了文件类型和对此文件进行各种操作函数的指针。对于大多数文件,v节点还包含了该文件的i节点(i-node,索引节点)。这些信息是在打开文件时从磁盘上读入内存的,所以,文件的所有相关信息都是随时可用的。例如,i节点包含了文件的所有者、文件长度、指向文件实际数据块在磁盘上所在位置的指针等
上图显示了两个进程对应的三张表之间的关系。A进程中fd1和fd20 指向文件表中的同一项。故二者指向同一个文件。
然后我们看进程A和进程B 两个进程都有文件描述符指向文件表项的 73,这时两个进程共享同一个文件。操作会同步。这种情况会出现在 fork子进程中。
进程A中fd0 指向文件表项0,进程B中fd3指向文件表项86。两项最终指向的 i-node是相同的,这就是说二者都打开了同一个文件。这就是一般情况下的二者处理同一个文件,但是二者处理的位置和处理方式都是各自管理的。
了解了内核中的这些数据结构,就可以解决上述问题。
- 多个进程可以同时打开同一个文件吗?此时他们的文件描述符是不是一样的?每个进程对文件进行读写的时候其他进程可以感知到吗?可以同时在同一个位置写入数据吗?将文件描述符发送给其他进程是不是可以共享文件描述符?
可以打开同一个文件,文件描述符的值可能会一样,有可能不一样。但是一般情况下,文件描述符中的文件表项指针不一样。 一般情况下某个进程读写时,其他进程感知不到,因为每个文件表项都维护自己的当前文件偏移量。 可以在同一个位置写数据但是会覆盖掉其中一个。 单纯将文件描述符的值发送给其他进程无法共享文件描述符,只有将文件表项指针发送给对方才可以共享文件描述符。
- 同一个进程是否可以用不同数值的文件描述符操作同一个文件?
可以
- 为什么文件可以重定向?重定向的原理?
多个文件描述符指向同一文件表项即是文件重定向。
UNIX也提供了一些函数来使用和管理上述的三个结构。
dup和dup2 函数可以复制文件描述符。
fcntl函数可以获取和修改文件描述符标志和文件状态标志。
具体函数使用和功能看man文档
对 i-node表项的获取和修改将在第四章学习。
参考链接:
https://www.jianshu.com/p/cded914786d5
原创文章,作者:1402239773,如若转载,请注明出处:https://blog.ytso.com/276565.html