C 标准库的 I/O 缓冲区
用户程序调用 C 标准 I/O 库函数读写文件或设备,而这些库函数要通过系
统调用把读写请求传给内核(以后我们会看到与 I/O 相关的系统调用),最终
由内核驱动磁盘或设备完成 I/O 操作。C 标准库为每个打开的文件分配一个 I/O
缓冲区以加速读写操作,通过文件的 FILE 结构体可以找到这个缓冲区,用户调
用读写函数大多数时候都在 I/O 缓冲区中读写,只有少数时候需要把读写请求
传给内核。
以 fgetc/fputc 为例,当用户程序第一次调用 fgetc 读一个字节时,fgetc
函数可能通过系统调用进入内核读 1K 字节到 I/O 缓冲区中,然后返回 I/O 缓冲
区中的第一个字节给用户,把读写位置指向 I/O 缓冲区中的第二个字符,以后
用户再调 fgetc,就直接从 I/O 缓冲区中读取,而不需要进内核了,当用户把这
1K 字节都读完之后,再次调用 fgetc 时,fgetc 函数会再次进入内核读 1K 字
节到 I/O 缓冲区中。
在这个场景中用户程序、C 标准库和内核之间的关系如图 1,C 标准库之所
以会从内核预读一些数据放在 I/O 缓冲区中,是希望用户程序随后要用到这些
数据,C 标准库的 I/O 缓冲区也在用户空间,直接从用户空间读取数据比进内
核读数据要快得多。另一方面,用户程序调用 fputc 通常只是写到 I/O 缓冲区
中,这样 fputc 函数可以很快地返回,如果 I/O 缓冲区写满了,fputc 就通过系
统调用把 I/O 缓冲区中的数据传给内核,内核最终把数据写回磁盘。有时候用
户程序希望把 I/O 缓冲区中的数据立刻传给内核,让内核写回设备,这称为
Flush 操作,对应的库函数是 ush,fclose 函数在关闭文件之前也会做 Flush
操作。
下图以 fgets/fputs 示意了 I/O 缓冲区的作用,使用 fgets/fputs 函数时在
用户程序中也需要分配缓冲区(图中的 buf1 和 buf2),注意区分用户程序的
缓冲区和 C 标准库的 I/O 缓冲区。
图 1C 标准库的 I/O 缓冲区
评论0