linux 内核通过三个数据结构表示打开的文件。记录项、文件表项、V节点。其三者关系大致如下:
- 进程表项中,记录中文件描述符与文件表项的关系;
- 文件表项中,记录文件状态标志位、当前文件偏移量、V节点指针;
- V节点中,记录文件类型、各种操作函数指针、指向i节点。而i节点包含文件的详细信息,比如:文件的所有者、文件长度、指向文件实际数据块再磁盘上所在位置的指针等。
注意:每一个文件只有一个唯一的V节点表;多个文件表项可以指向同一个V节点表,每调用一次open
,则创建一个新的文件表项;不同fd可以指向同一个文件表项;即可能存在以下场景:
正是这样的机制原理,linux 让我们可以多任务同时访问同一文件。但是在写文件时,我们需要关注写入时序以及数据错乱问题。
- 在完成每一个
read
或write
操作后,文件表项中的当前文件偏移量增加所读写的字节数。 - 如果使用O_APPEND标志打开一个文件,则响应标志也被设置到文件表项的文件状态标志中。每次进行写操作时,文件表项中的当前文件偏移量首先会被设置为表项中的文件长度。这就确保每次写入的数据追加到当前尾端处。
- lseek 函数只是修改文件表项中的当前文件偏移量,不进行任何I/O操作。
- 每一个进程都有它自己的文件表项和进程表项。