编程语言
首页 > 编程语言> > UNIX环境高级编程 - 文件I/O - 读写/共享文件

UNIX环境高级编程 - 文件I/O - 读写/共享文件

作者:互联网

函数lseek

使用 lseek 函数显式的为一个打开文件设置偏移量。

每个打开的文件都有一个与其关联的“当前文件偏移量”。它通常是个非负整数,用于度量从文件开始处计算的字节数。

读、写操作都从当前文件偏移量处开始,并使偏移量增加所读写的字节数。

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

一些关于 lseek 和文件偏移量的注意事项:

函数read

调用 read 函数从打开文件中读取数据。

读操作从文件的当前偏移量开始,在成功返回之前,文件的当前偏移量会增加实际读到的字节数

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t nbytes);

有多种情况可能导致实际读到的字节数少于期望读到的字节数

函数write

#include <unistd.h>

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

write 的返回值通常都是与 nbytes 相同。否则表示出错。

write 出错的一个常见原因是磁盘写满,或者超过了一个给定进行的文件长度限制

对于普通文件,写操作从文件的当前偏移量处开始。如果打开文件时指定了 O_APPEND 选项,则每次写操作之前,都会将文件偏移量设置在文件的当前结尾处。在一次成功写之后,该文件偏移量增加实际写的字节数。

I/O效率

下图显示了用 20 种不同的缓冲区长度,读 516,581,760 字节的文件所得到的结果:

image-20211105102521542

此测试所用的文件系统是 Linux ext4 文件系统,其磁盘块长度为 4096 字节(4K)。

  1. 系统 CPU 时间的几个最小值差不多出现在 BUFFSIZE 为 4096 及以后的位置,继续增加缓冲区长度对此时间几乎没有影响。
  2. 缓冲区长度小至 32 字节时的时钟时间与拥有较大缓冲区长度时的时钟时间几乎一样。

Why?

大多数文件系统为改善性能都采用某种预读(read ahead)技术。当检测到正进行顺序读取时,系统就试图读入比应用所要求的更多数据,并假想应用很快就会读这些数据。(利用了局部性原理)

文件共享

UNIX 系统支持在不同进程间共享打开文件。

内核使用三种数据结构描述打开文件。它们之间的关系决定了一个进程与另一个进程在打开的文件之间的相互影响。

  1. 内核为每个进程分配一个进程表项(所有进程表项构成进程表),进程表中都有一个打开的文件描述符表。每个文件描述符占用一项,其内容为:

    • 文件描述符标志
    • 指向一个文件表项的指针
  2. 内核为每个打开的文件分配一个文件表项(所有的文件表项构成文件表)。每个文件表项的内容包括:

    • 文件状态标志(读、写、添写、同步和阻塞等)
    • 当前文件偏移量
    • 指向该文件 v 结点表项的指针
  3. 每个打开的文件或者设备都有一个 v 结点结构(v-node)。 v 结点结构的内容包括:

    • 文件类型和对此文件进行各种操作函数的指针。
    • 对于大多数文件, v 结点还包含了该文件的 i 结点。

    这些信息都是在打开文件时从磁盘读入内存的。如 i 结点包含了文件的所有者、文件长度、指向文件实际数据在磁盘上所在位置的指针等等。 v 结点结构和 i 结点结构实际上代表了文件的实体。

Linux 没有将相关数据结分为 i 节点和 v 节点,而是采用了一个与文件系统相关的 i 节点和个与文件系统无关的 i 节点。

一个进程打开多个文件:

image-20211105110323154

两个进程打开同一个文件:

image-20211105110351724

可能有多个文件描述符指向同一个文件表项。(dup、fork)

dup的情况:

image-20211105111106514

fork的情况:

image-20211105111025894

标签:文件,表项,字节数,lseek,读写,偏移量,UNIX,打开
来源: https://www.cnblogs.com/cxl-/p/15512340.html