Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1426367
  • 博文数量: 842
  • 博客积分: 12411
  • 博客等级: 上将
  • 技术积分: 5772
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-14 14:43
文章分类

全部博文(842)

文章存档

2013年(157)

2012年(685)

分类: 系统运维

2012-05-14 17:23:32



标准I/O库提供的缓冲的目的是使用最少的read和write调用。(回想第3章我们展示了使用各种缓冲的尺寸执行I/O所需要的CPU时间。)此外,它尝试为每个I/O流进行缓冲,消除程序担心它的需要。不幸的是,标准I/O库产生最多混淆的就是缓冲。


有三种缓冲类型被提供:


1、完全缓冲(Fully buffered)在这种情况下,当标准I/O的缓冲被填满后,真实的I/O才会发生。在磁盘上的文件通常都被标准I/O库完全缓冲。这个被使用的缓冲通常被标准I/O库在第一次操作一个流时通过调用malloc得到(7.8节)。


术语“冲洗(flush)”描述了标准I/O缓冲的写操作。一个缓冲可以被标准I/O函数自动冲洗,比如在缓冲满时,或者我们可以调用函数fflush来 冲洗一个流。不幸的是,在UNIX环境里,冲洗有两个意思。在标准I/O库里,它表示缓冲的内容写出,它可能是部分填充的。在终端设备的术语里,比如18 章的tcflush函数,它表示丢弃缓冲里存储的数据。


2、行缓冲(Line buffered)。在这种情况下,标准I/O库在输入输出时碰到一个换行符时会执行I/O操作。这让我们可以一次输出单个字符(使用标准I/O的 fputc函数),因为我们知道只当我们完成了每行的写操作时真实I/O才会发生。行缓冲被典型用在终端的流上:比如标准输入、标准输出。


行缓冲伴随两个警告。第一,标准I/O库用来收集各行的缓冲区大小是固定的,所以当我们在写一个换行符之前填满这个缓冲I/O可能会发生。第二、不管何时 通过标准I/O库从a、一个未缓冲流或b、(需要从内核被请求数据的)一个行缓冲流请求一个输入时,所有行缓冲输出流都会被冲洗。b情况括号内的补充条件 的原因是,请求的数据可能已经在缓冲里了,这时不再需要从内核中读取数据。显然,a情况下任何从未缓冲流的输入,都会要求从内核获取数据。


3、无缓冲(Unbuffered)。标准I/O库不缓冲字符。例如,如果我们用标准I/O函数fputs写15个字符,我们会期望这15个字符尽快地输出,它很可能使用了3.8节的write函数。

例如,标准错误流通常是无缓冲的。这是为了使任何错误消息都能尽快地显示,而不管它们是否包含一个换行符。


ISO C定义了以下缓冲性质:

1、当且仅当它们没有指向交互式的设备,标准输入和标准输出为完全缓冲的。


2、标准错误绝不是完全缓冲的。


然而,这里没有告诉我们如果标准输入和标准输出表示交互式的设备时,它们是无缓冲的还是行缓冲的;又或者标准错误是无缓冲的还是行缓冲的。多数实现默认使用以下的缓冲类型:

1、标准错误总是无缓冲的。


2、所有其它流,如果它们指向一个终端设备,都是行缓冲的;否则,它们是完全缓冲的。


本文讨论的四个平台遵守了这些协定:标准错误是无缓冲的,为终端设备打开的流是行缓冲的,而所有其它流是完全缓冲的。


我们会在5.12节更详细地介绍标准I/O的缓冲。


如果我们不喜欢任何给定流的这些默认行为,我们可以通过调用下面两个函数的其中一个来改变缓冲:



  1. #include <stdio.h>

  2. void setbuf(FILE *restrict fp, char *restrict buf);

  3. void setvbuf(FILE *restrict fp, char *restrict buf, int mode, size_t size);

  4. 成功返回0,失败返回非0值。


这些函数必须在流打开后(显然,因为它们第一个参数都是一个合法文件指针),但在这个流上执行任何操作之前调用。


通过setbuf,我们可以打开或关闭缓冲。要开启缓冲,buf必须是指向长度为BUFSIZ的缓冲的指针,这个常量定义 在里。通常,这个流是完全缓冲的,但是如果这个流与一个终端设备关联的话,一些系统可能会设置成行缓冲。要禁用缓冲,我们 把buf设置为NULL。


通过setvbuf,我们精确地指定我们想要的缓冲类型。这通过mode参数来完成:


_IOFBF:完全缓冲的;


_IOLBF:行缓冲的;


_IONBF:无缓冲的。


如果我们指定一个无缓冲的流,buf和size参数会被忽略。如果我们指定完全缓冲或行缓冲,buf和size可以选择性地指定一个缓冲和它的尺寸。如果 流是缓冲的而buf是NULL,标准I/O库会自动使用恰当的尺寸为这个流开辟它自己的缓冲。恰当的尺寸表示由BUFSIZ常量指定的值。


一些C库的实现使用stat结构体的st_blksize成员的值(参考4.2节)来决定优化的标准I/O缓冲大小。我们将在本章的后面部分看到,GNU C库使用了这种方法。


下表总结了这两个函数的行为以及它们的各种选项:

setbuf和setvbuf函数汇总
函数 mode buf 缓冲和长度 缓冲类型
setbuf   非null 长度为BUFSIZ的用户buf 完全缓冲或行缓冲
NULL (没有缓冲) 无缓冲的
setvbuf _IOFBF 非null 长度为size的用户buf 完全缓冲
NULL 合适长度的系统缓冲
_IOLBF 非null 长度为size的用户buf 行缓冲
NULL 合适长度的系统缓冲
_IONBF (忽略) (没有缓冲) 无缓冲的

注意如果我们在一个函数里用一个自动变量(automatic variable)开辟一个标准I/O的缓冲作,我们必须在从函数返回前关闭这个流。(我们将在7.8节更多讨论。)还有,一些实现为内部记账 (internal bookkeeping)而使用这个缓冲的一部分,所以可以存储在这个缓冲的数据的真实字节数要比它的尺寸小。一般来说,我们应该让系统选择缓冲尺寸并自 动地开避这个缓冲。当我们这样做时,在我们关闭这个流时,标准I/O库自动地释放这个缓冲。


任何时候,我们可以强制一个流的冲洗。



  1. #include <stdio.h>

  2. int fflush(FILE *fp);

  3. 成功返回0,失败返回EOF。


这个函数导致流中任何未写的数据都被传递级内核。作为一个特殊情况,如果fp为NULL,函数会冲洗所有的输出流。

阅读(662) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~