标准I/O缓冲区是用于提高I/O性能的一种机制,它位于标准C库中,并由标准I/O函数自动管理。标准I/O库通过在内存中创建缓冲区来减少频繁的系统调用,从而提高读写操作的效率。
当使用全缓冲模式时,标准I/O库会在内存中创建一个较大的缓冲区(通常大小为BUFSIZ),直到缓冲区被填满或遇到换行符('\n')时才会将数据写入磁盘。全缓冲适用于文件和大量数据的I/O操作,减少了系统调用的次数,提高了效率。
行缓冲模式下,标准I/O库会在遇到换行符('\n')时将数据写入磁盘,或者当缓冲区被填满时也会进行写入。行缓冲适用于终端设备(如终端窗口),可以保证每行数据都及时输出,方便用户查看输出结果。
无缓冲模式下,标准I/O库会立即将数据写入磁盘,不使用缓冲区。每次调用I/O函数都会导致实际的系统调用,适用于需要立即刷新数据到磁盘的场景,如实时输出错误信息。
标准I/O函数会自动选择合适的缓冲模式,但你也可以使用setvbuf
函数来显式地设置缓冲模式和自定义缓冲区。
对于标准输入(stdin)、标准输出(stdout)和标准错误(stderr),它们的默认缓冲模式通常是行缓冲(对于交互式终端)或全缓冲(对于文件和重定向)。
需要注意的是,标准I/O缓冲区是由C库管理的,所以在使用标准I/O函数时,要确保及时刷新缓冲区,以免数据在缓冲区中滞留而未及时输出。可以使用fflush
函数来手动刷新缓冲区,确保数据及时写入磁盘或终端。
setbuf
函数用于设置标准I/O流的缓冲区,从而控制I/O的缓冲方式。它允许你自定义缓冲区,或者禁用缓冲。setbuf
函数的原型如下:
#include
void setbuf(FILE *stream, char *buffer);
参数说明:
stream
:指向要设置缓冲区的文件流,可以是标准输入(stdin)、标准输出(stdout)、标准错误(stderr)或者其他已打开的文件流。
buffer
:指向自定义缓冲区的指针。如果传递NULL,则表示禁用缓冲,使I/O变为无缓冲。
setbuf
函数允许两种方式的缓冲:
全缓冲:如果buffer
指向一个大小大于0的缓冲区,那么I/O操作将使用全缓冲模式。这意味着在填满整个缓冲区或者遇到换行符('\n')时,才会进行实际的I/O操作。
无缓冲:如果buffer
为NULL,或者大小为0,那么I/O操作将变为无缓冲模式。这意味着每次调用输出函数(printf
、putchar
等)或者输入函数(scanf
、getchar
等),都会立即进行I/O操作,而不会在内存中缓冲数据。
在使用setbuf
函数时,要注意以下几点:
调用setbuf
函数应该在打开文件流或者任何I/O操作之前,否则可能不会生效。
如果要使用自定义的缓冲区,确保缓冲区足够大,以避免缓冲区溢出。
如果设置为无缓冲,要注意频繁的I/O操作可能会导致性能下降,因为每次调用I/O函数都会进行实际的I/O操作,这会增加系统开销。
当使用自定义缓冲区时,不要在buffer
指向的缓冲区被释放或者失效后再进行I/O操作,以免导致未定义的行为。
示例:使用全缓冲模式设置标准输出(stdout)的缓冲区为一个大小为BUFSIZ(通常是1024字节)的缓冲区。
#include
int main() {
char buf[BUFSIZ];
setbuf(stdout, buf);
printf("This will be buffered\n");
fflush(stdout); // 强制刷新缓冲区,立即输出
printf("This will also be buffered\n");
return 0;
}
示例:禁用标准输出(stdout)的缓冲区,使其变为无缓冲模式。
#include
int main() {
setbuf(stdout, NULL); // 禁用缓冲
printf("This will be immediately output\n");
printf("No buffering in this case\n");
return 0;
}
setvbuf
函数也是用于设置标准I/O流的缓冲方式,与setbuf
函数类似,但提供更灵活的缓冲控制。setvbuf
函数允许你自定义缓冲区,并且可以指定缓冲类型,包括全缓冲、行缓冲和无缓冲。它的原型如下:
#include
int setvbuf(FILE *stream, char *buffer, int mode, size_t size);
参数说明:
stream
:指向要设置缓冲区的文件流,可以是标准输入(stdin)、标准输出(stdout)、标准错误(stderr)或者其他已打开的文件流。
buffer
:指向自定义缓冲区的指针。如果传递NULL,则会使用系统默认的缓冲区。
mode
:指定缓冲类型,可以是以下值之一:
_IOFBF
:全缓冲模式。使用指定的缓冲区,并在填满整个缓冲区时才进行实际的I/O操作。
_IOLBF
:行缓冲模式。使用指定的缓冲区,并在遇到换行符('\n')时才进行实际的I/O操作。
_IONBF
:无缓冲模式。禁用缓冲,每次调用I/O函数都会立即进行实际的I/O操作。
size
:指定缓冲区大小。对于全缓冲和行缓冲模式,size
表示缓冲区大小;对于无缓冲模式,size
被忽略,可以设置为0。
setvbuf
函数的返回值是非零值表示成功,返回0表示失败。
另外在使用setvbuf
函数时,可以根据需要设置不同类型的缓冲模式和缓冲区大小。对于全缓冲和行缓冲,需要确保缓冲区足够大,以避免缓冲区溢出。而对于无缓冲模式,要注意频繁的I/O操作可能会导致性能下降。
示例:使用全缓冲模式设置标准输出(stdout)的缓冲区为一个大小为BUFSIZ(通常是1024字节)的缓冲区。
#include
int main() {
char buf[BUFSIZ];
setvbuf(stdout, buf, _IOFBF, BUFSIZ);
printf("This will be buffered\n");
fflush(stdout); // 强制刷新缓冲区,立即输出
printf("This will also be buffered\n");
return 0;
}
示例:使用行缓冲模式设置标准输出(stdout)的缓冲区。
#include
int main() {
char buf[BUFSIZ];
setvbuf(stdout, buf, _IOLBF, BUFSIZ);
printf("This will be line buffered\n");
printf("This will also be line buffered\n");
return 0;
}
示例:禁用标准输出(stdout)的缓冲区,使其变为无缓冲模式。
#include
int main() {
setvbuf(stdout, NULL, _IONBF, 0); // 禁用缓冲
printf("This will be immediately output\n");
printf("No buffering in this case\n");
return 0;
}
但要注意:在某些系统上,对标准输入(stdin)和标准输出(stdout)的缓冲设置可能不会生效,因为它们是由标准库提供的,并且可能使用了系统默认的缓冲设置。所以在实际使用中,最好将setvbuf
函数用于文件流而不是标准输入和标准输出。
更多C语言和Linux系统相关文章,关注专栏:
手撕C语言
玩转linux
一键三连喔
~