15.13 改变缓冲方式
在流上执行的缓冲方式有时并不合适,下面两个函数可以用于对缓冲方式进行修改。只有当指定的流被打开但还没有在它上面执行任何操作前,才能调用这两个函数。
void setbuf( FILE *stream, char *buf );
int setvbuf( FILE *stream, char *buf, int mode, size_t size );
setbuf设置了另一个数组,用于对流进行缓冲。这个数组的字符长度必须为BUFSIZ(定义于stdio.h)。为一个流自行指定缓冲区可以防止I/O函数库为它动态分配一个缓冲区。如果用一个NULL参数调用这个函数,setbuf函数将关闭流的所有缓冲方式。字符准确地按程序所规定的方式进行读取和写入。
在宿主式运行时环境中,操作系统可能有自己的缓冲方式,而不依赖于流。因此,仅仅调用setbuf将不允许从键盘即输即读字符,因为操作系统通常对这些字符进行缓冲,用于实现退格编辑。
/*
** setbuf。
*/
#include <stdio.h>
#include <stdlib.h>
int main( void ){
/*
** buf is a local auto array, this is a dangerous operation to use local auto array
** as buffer zone of stream.
*/
char buf[BUFSIZ];
FILE *file;
file = fopen( "data_source.txt", "r" );
setbuf( file, buf );
while( fgets( buf, 5, file ) ){
fputs( buf, stdout );
}
fclose( file );
return EXIT_SUCCESS;
}
/* 输出:

*/
警告:
为流缓冲使用一个自动数组是很危险的。如果在流关闭之前,程序的执行流离开了数组声明所在的代码块,流就会继续使用这块内存,但此时它可能已经分配给了其他函数。
setvbuf函数更为通用。mode参数用于指定缓冲的类型。其中,_IOFBF指定一个完全缓冲的流,_IONBF指定一个不缓冲的流,_IOLBF指定一个行缓冲流。所谓行缓冲流,就是每当一个换行符写入到缓冲区时,缓冲区便进行刷新。
buf和size参数用于指定需要使用的缓冲区。如果buf为NULL,那么size的值必须是0。一般而言,最好用一个长度为BUFSIZ的字符数组作为缓冲区。尽管使用一个非常大的缓冲区可能会稍微提高程序的效率,但如果使用不当,也有可能降低程序的效率。例如,绝大多数操作系统在内部对磁盘的输入/输出进行缓冲操作。如果自行指定了一个缓冲区,但它的长度却不是操作系统内部使用的缓冲区的整数倍,就可能需要一些额外的磁盘操作,用于读取或写入一个内存块的一部分。如果需要使用一个很大的缓冲区,它的长度应该是BUFSIZ的整数倍,缓冲区的大小如果和磁盘簇的大小相匹配,可能会提高一些效率。