Linux输入输出的I/O缓冲

    以前写C程序输入输出并没有特意关注过I/O缓冲区的问题。最近在学习fork的时候,发现I/O缓冲区是需要关注的一个细节问题。I/O缓冲区是Unix支持的一项标准,并且得到ISO C标准的支持。

其作用:

    标准I/O库提供缓冲的目的是尽可能减少外部设备数据读写read和write的次数,从而加快CPU的工作效率。

缓冲区的大小:

    缓冲区的大小等于外部块设备的一个块长大小时效率最好。所谓块设备,就是以一块一块的数据存取的设备;字符设备是一次存取一个字符的设备。磁盘、内存都是块设备,字符设备如键盘和串口。

    如果不想使用系统默认的缓冲区大小,可以使用setvbuf函数来自定义缓冲区大小。也可以用setbuf函数开/关缓冲机制。

缓冲区冲洗(flush):
    缓冲区是一个数据暂存区,那么冲洗的意思就是“清仓”,将缓冲区当前的内容全部写到外部设备上去。该操作可由标准I/O例程自动flush,或者由程序员调用fflush函数。

    程序遇到“\n”(仅限行缓冲),或是EOF,或是缓冲区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。

缓冲类型:

    标准I/O提供了三种类型,下面说下他们的概念和常用场合:

1、全缓冲

    在I/O操作时,只有当I/O缓冲区被填满时,才进行真正的I/O操作。对于全缓冲的缓冲区可由标准I/O例程自动刷新。还有一种方法就是调用函数fflush进行刷新。

    对于驻留在磁盘上的文件,通常由标准I/O库实施全缓冲

2、行缓冲

    在I/O操作时,输入输出遇到换行符'\n'时进行,才进行真正的I/O操作。对于行缓冲,要注意量点:第一,标准I/O每一行缓冲区的最大长度是固定的,所以只要填满了缓冲区,即使没有遇到换行符也要冲洗缓冲区。第二,当使用行缓冲作输出缓冲区时,若输入流是不带缓冲区的流或者一个行缓冲区的流,那么要直接冲洗输出的行缓冲区。前者是因为不缓冲区的输入要求必须马上输出,后者是因为已经输入时做好了缓冲,不必重复缓冲。

    当流涉及到一个终端时,比如标准输入stdin和标准输出stdout,通常使用行缓冲。scanf、printf不直接调用系统调用,在用户空间维护一块行缓冲区,在适当的时候调用read、 write读写缓冲区。

3、不带缓冲

    底层函数数据读写函数read和write是不带缓冲区的,直接调用系统调用进行外部读写。标准出错流stderr是不带缓冲的,这样能使得错误信息尽快显示


例子:下面加入sleep的例子有助于看出标准输出行缓冲的作用。

#include <stdio.h>
void main()
{
	for(int j=0;j<3;j++)
	{
		for(int i=0;i<5;i++)
		{
			printf("-");
			sleep(2);
		}
		sleep(2);
		printf("@\n");
	}
}

注意:虽然上面说的都是输入输出。但实际上主要是在将标准输出,即内存数据写到外部终端设备。这是因为内存处理速度快,终端显示设备速度慢。与之相对应的情况,从键盘设备读到内存中,之间也有行缓冲区。所区别的是,当冲洗缓冲区的时候,缓冲区的内容会被丢弃,而不是读到内存中。这个并没有成为IOS C标准。所以APUE中没怎么提到。 (源自APUE第3、5章)



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux的文件I/O操作可以使用系统调用来实现。其中,常用的系统调用有open、read、write、close等。 open是打开文件的系统调用,可以指定文件的路径、打开模式等参数。例如,打开一个文件并返回一个文件描述符的代码如下: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int fd; fd = open("test.txt", O_RDONLY); if(fd == -1) { perror("open"); return 1; } printf("File descriptor: %d\n", fd); return 0; } ``` read是读取文件的系统调用,可以指定读取的文件描述符、缓冲区地址、读取的字节数等参数。例如,读取一个文件并输出其内容的代码如下: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> #define BUF_SIZE 1024 int main() { int fd, n; char buf[BUF_SIZE]; fd = open("test.txt", O_RDONLY); if(fd == -1) { perror("open"); return 1; } while((n = read(fd, buf, BUF_SIZE)) > 0) { write(STDOUT_FILENO, buf, n); } close(fd); return 0; } ``` write是写入文件的系统调用,可以指定写入的文件描述符、缓冲区地址、写入的字节数等参数。例如,将用户输入的内容写入一个文件的代码如下: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> #define BUF_SIZE 1024 int main() { int fd, n; char buf[BUF_SIZE]; fd = open("test.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); if(fd == -1) { perror("open"); return 1; } while((n = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) { write(fd, buf, n); } close(fd); return 0; } ``` close是关闭文件的系统调用,可以指定要关闭的文件描述符。例如,关闭一个文件的代码如下: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> int main() { int fd; fd = open("test.txt", O_RDONLY); if(fd == -1) { perror("open"); return 1; } // do something close(fd); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值