标准I/O库之缓冲


标准I/O库提供缓冲的目的是尽可能减少使用read和write调用的次数。它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的麻烦。

标准I/O提供了三种类型的缓冲:

(1)全缓冲。这种情况下,。对于驻留在磁盘上的文件通常是由标准I/O库实施全缓冲的。在一个流上执行第一次I/O操作时,相关标准I/O函数通常调用malloc获得需使用的缓冲区。

。缓冲区可由标准I/O例程自动冲洗(例如当填满一个缓冲区时),或者可以调用函数fflush冲洗一个流。值得引起注意的是在UNIX环境中,flush有两种意思:(该缓冲区可能只是局部填写的)。在终端驱动程序方面,flush(刷清)表示丢弃已存储在缓冲区中的数据。

(2)行缓冲。在这种情况下,当。这允许我们一次输出一个字符(用标准I/O fputc函数,该函数一次只输出一个字符,没有换行符),但只有在写了一行之后才进行实际I/O操作。当流涉及一个终端时(例如标准输入和标准输出),通常使用行缓冲。

对于行缓冲有两个限制。第一,因为标准I/O库用来收集每一行的缓冲区的长度是固定的,所以只要填满了缓冲区,那么即使还没有写一个换行符,也进行I/O操作。第二,任何时候只要通过标准I/O库要求从(a)一个不带缓冲的流,或者(b)一个行缓冲的流(它要求从内核得到数据)得到输入数据,那么就会造成冲洗所有行缓冲输出流。在(b)中带了一个括号中的说明,其理由是,所需的数据可能已在该缓冲区中,它并不要求在需要数据时才从内核读数据。很明显,从不带缓冲的一个流中进行输入((a)项)要求当时从内核得到数据。

(3)不带缓冲。例如,如果用标准I/O函数fputs写15个字符到不带缓冲的流中,则该函数很可能用write系统调用函数将这些字符立即写到相关联的打开文件上。

标准出错流stderr通常是不带缓冲的,这就使得出错信息可以尽快显示出来,而不管它们是否含有一个换行符。

ISO C要求下列缓冲特征:

  • 当且仅当标准输入和标准输出并不涉及交互式设备时,它们才是全缓冲的。
  • 标准出错绝不会是全缓冲的。

但是,这并没有告诉我们如果标准输入和输出涉及交互式设备时,它们是不带缓冲的还是行缓冲的;以及标准出错是不带缓冲的还是行缓冲的。很多系统默认使用下列类型的缓冲:

  • 标准出错是不带缓冲的。
  • 如若是涉及终端设备的其他流,则它们是行缓冲的;否则是全缓冲的。

对任何一个给定的流,如果我们并不喜欢这些系统默认的情况,则可调用下列两个函数中的一个更改缓冲类型:

#include <stdio.h>
 setbuf( FILE *restrict fp,  * setvbuf( FILE *restrict fp,  *restrict buf, 

。为了带缓冲进行I/O,参数buf必须指向一个长度为BUFSIZE的缓冲区(该常量定义在<stdio.h>中)。通常在此之后该流就是全缓冲的,但是如果流与一个终端相关,那么某些系统也可将其设置为行缓冲。

使用setvbuf,我们可以精确地指定所需的缓冲类型。这是用mode参数实现的:

_IOFBF 全缓冲
_IOLBF 行缓冲
_IONBF 不带缓冲

如果指定一个不带缓冲的流,则忽略buf和size参数。如果指定全缓冲或行缓冲,则buf和size可选择地指定一个缓冲区及其长度。如果该流是带缓冲的,而buf是NULL,则标准I/O库将自动地为该流分配适当长度的缓冲区。适当长度指的是由常量BUFSIZE所指定的值。

某些C函数库实现使用stat结构中的成员st_blksize所指定的值决定最佳I/O缓冲区长度。GNU C函数库就使用这种方法。

表5-1列出了这两个函数的动作,以及它们的各个选项。

fflush( FILE *

。作为一个特例,如若fp是NULL,则此函数将导致所有输出流被冲洗。

相关内容