转自:http://blog.csdn.net/lmh12506/article/details/6803847

首先要明白不带缓冲的概念:所谓不带缓冲,并不是指内核不提供缓冲,而是只单纯的系统调用,不是函数库的调用。系统内核对磁盘的读写都会提供一个块缓冲,当用write函数对其写数据时,直接调用系统调用,将数据写入到块缓冲进行排队,当块缓冲达到一定的量时,才会把数据写入磁盘。因此所谓的不带缓冲的I/O是指进程不提供缓冲功能(但内核还是提供缓冲的)。每调用一次write或read函数,直接系统调用。
而带缓冲的I/O是指进程对输入输出流进行了改进,提供了一个流缓冲,当用fwrite函数网磁盘写数据时,先把数据写入流缓冲区中,当达到一定条件,比如流缓冲区满了,或刷新流缓冲,这时候才会把数据一次送往内核提供的块缓冲,再经块缓冲写入磁盘。(双重缓冲)
因此,带缓冲的I/O在往磁盘写入相同的数据量时,会比不带缓冲的I/O调用系统调用的次数要少。
下面的东西是我从网上查到的对这两者的理解,我觉得还是很到位的:

以下主要讨论关于open,write等基本系统IO的带缓冲与不带缓冲的差别

带缓存的文件操作是标准C库的实现,第一次调用带缓存的文件操作函数时标准库会自动分配内存并且读出一段固定大小的内容存储在缓存中。所以以后每次的读写操作并不是针对硬盘上的文件直接进行的,而是针对内存中的缓存的。何时从硬盘中读取文件或者向硬盘中写入文件有标准库的机制控制。不带缓存的文件操作通常都是系统提供的系统调用, 更加低级,直接从硬盘中读取和写入文件,由于IO瓶颈的原因,速度并不如意,而且原子操作需要程序员自己保证,但使用得当的话效率并不差。另外标准库中的带缓存文件IO 是调用系统提供的不带缓存IO实现的。

“术语不带缓冲指的是每个read和write都调用内核中的一个系统调用。所有的磁盘I/O都要经过内核的块缓冲(也称内核的缓冲区高速缓存),唯一例外的是对原始磁盘设备的I/O。既然read或write的数据都要被内核缓冲,那么术语“不带缓冲的I/O“指的是在用户的进程中对这两个函数不会自动缓冲,每次read或write就要进行一次系统调用。“--------摘自<unix环境编程>

程序中用open和write打开创建并把“hello world“写入文件test.txt,相应用fopen和fwrite操作文件test2.txt。程序执行到open和fopen之后,sleep 15秒,这时用ls查看生成了文件没,这时用open打开的test.txt出现了,用fopen打开的的test2.txt也出现了;当程序执行完write和 fwrite之后,在15秒睡眠期间,用cat查看test.txt,其内容是“hello,world”;但是此时用cat查看test2.txt,其内容为空。睡眠结束后,执行了close(fd),此时再用cat查看test2.txt,发现其内容也有了:“hello,world”。该例子证明了open和write是不带缓冲的,即程序一执行其io操作也立即执行,不会停留在系统提供的缓冲里,不需等到close操作完才执行。与之相比的fopen和fwrite则是带缓冲的,(一般)要等到fclose操作完后才会执行。

相关的源码示例如下:

#include <unistd.h>
#include <iostream>
#include <fcntl.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h> using namespace std; int main(){
int fd;
FILE *file;
char *s="hello,world\n";
if((fd=open("test.txt",O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1){
cout<<"Error open file"<<endl;
return -1;
}
if((file=fopen("test2.txt","w"))==NULL){
cout<<"Error Open File."<<endl;
return -1;
}
cout<<"File has been Opened."<<endl;
sleep(15);
if(write(fd,s,strlen(s))<strlen(s)){
cout<<"Write Error"<<endl; return -1;
}
if(fwrite(s,sizeof(char),strlen(s),file)<strlen(s)){
cout<<"Write Error in 2."<<endl; return -1;
}
cout<<"After write"<<endl; sleep(15);
cout<<"After sleep."<<endl; close(fd);
return 0;
}

详情请见:http://blog.csai.cn/user1/27828/archives/2007/14285.html

以 ssize_t write(int filedes, const void *buff, size_t nbytes)和size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp)来讲讲自己对unix系统下带缓存的I/O和不带缓存的I/O的区别。

首先要清楚一个概念,所谓的带缓存并不是指上面两个函数的buff参数。

当将数据写到文件上时,内核先将该数据写到缓存,如果该缓存未满,则并不将其排入输出队列,直到缓存写满或者内核再次需要重新使用此缓存时才将其排入输入队列,待其到达队首,再进行实际的I/O操作,也就是此时才把数据真正写到磁盘,这种技术叫延迟写。

现在假设内核所设的缓存是100个字节,如果你使用write,且buff的size为10,当你要把9个同样的buff写到文件时,你需要调用9次write,也就是9次系统调用,此时也并没有写到硬盘,如果想立即写到硬盘,调用fsync,可以进行实际的I/O操作。

标准I/O,也就是带缓存的I/O采用 FILE*,FILE实际上包含了为管理流所需要的所有信息:实际I/O的文件描述符,指向流缓存的指针(标准I/O缓存,由malloc分配,又称为用户态进程空间的缓存,区别于内核所设的缓存),缓存长度,当前在缓存中的字节数,出错标志等,假设流缓存的长度为50字节,把以上的数据写到文件,则只需要2次系统调用(fwrite调用write系统调用),因为先把数据写到流缓存,当其满以后或者调用fflush时才填入内核缓存,所以进行了2次的系统调用write。

fflush将流所有未写的数据送入(刷新)到内核(内核缓冲区),fsync将所有内核缓冲区的数据写到文件(磁盘)。

不带缓存的read和write是相对于 fread/fwrite等流函数来说明的,因为fread和fwrite是用户函数(3),所以他们会在用户层进行一次数据的缓存,而read/write是系统调用(2)所以他们在用户层是没有缓存的,所以称read和write是无缓存的IO,其实对于内核来说还是进行了缓存,不过用户层看不到罢了。

详情请见:http://blog.sina.com.cn/s/blog_4a92ce12010004ub.html

带缓冲I/O和不带缓冲I/O的区别与联系的更多相关文章

  1. 带缓冲I/O 和不带缓冲I/O的区别与联系

    首先要明白不带缓冲的概念:所谓不带缓冲,并不是指内核不提供缓冲,而是只单纯的系统调用,不是函数库的调用.系统内核对磁盘的读写都会提供一个块缓冲(在有些地方也被称为内核高速缓存),当用write函数对其 ...

  2. 少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

    1.引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO? 在本 ...

  3. 转: 带你玩转Visual Studio——带你理解多字节编码与Unicode码

    上一篇文章带你玩转Visual Studio——带你跳出坑爹的Runtime Library坑帮我们理解了Windows中的各种类型C/C++运行时库及它的来龙去脉,这是C++开发中特别容易误入歧途的 ...

  4. 带你玩转Visual Studio——带你了解VC++各种类型的工程

    原文地址:http://blog.csdn.net/luoweifu/article/details/48816605 上一篇文章带你玩转Visual Studio——带你新建一个工程一文中提到新建一 ...

  5. 带你玩转Visual Studio——带你理解微软的预编译头技术

    原文地址:http://blog.csdn.net/luoweifu/article/details/49010627 不陌生的stdafx.h 还记得带你玩转Visual Studio——带你新建一 ...

  6. 少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

    少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写 ...

  7. 带你玩转Visual Studio——带你理解多字节编码与Unicode码

    目录(?)[-] 多字节字符与宽字节字符 char与wchar_t string与wstring string 与 wstring的相关转换 字符集Charcater Set与字符编码Encoding ...

  8. 【转载】IIS网站配置不带www域名直接跳转带www的域名

    很多时候为了统一网站入口,需要将不带www的主域名解析到带www的域名记录下,当客户访问不带www的域名网址的时候自动跳转到带www的域名,在IIS Web服务器中可以通过URL重写模块来实现此功能, ...

  9. 带缓冲的IO和不带缓冲的IO

    文件描述符: 文件描述符是一个小的非负整数,是内核用来标识特定进程正在访问的文件 标准输入/输出/出错: shell为每个程序打开了三个文件描述符,STDIN_FILEON,STDOUT_FILEON ...

随机推荐

  1. spring+springMVC+JPA配置详解(使用缓存框架ehcache)

    SpringMVC是越来越火,自己也弄一个Spring+SpringMVC+JPA的简单框架. 1.搭建环境. 1)下载Spring3.1.2的发布包:Hibernate4.1.7的发布包(没有使用h ...

  2. CSS预处理器Sass(Scss)、Less、Stylus

    CSS 预处理编译器能让我成程序化其的方式编写CSS代码,可以引入CSS中没有的变量.条件.函数等特性,从而让代码更简单易维护,但一般按预处理器语法编写的代码无法直接在浏览器中运行,需用通过工具比如g ...

  3. HDU 5317 RGCDQ

    题意:f(i)表示i的质因子个数,给l和r,问在这一区间内f(i)之间任意两个数最大的最大公倍数是多少. 解法:先用筛法筛素数,在这个过程中计算f(i),因为f(i)不会超过7,所以用一个二维数组统计 ...

  4. iOS开发UI篇—实现一个私人通讯录小应用【转】

    转一篇学习segue不错的教程 一.该部分主要完成内容 1.界面搭建                        2.功能说明 (1).只有当账号和密码输入框都有值的时候,登录按钮才能交互 (2). ...

  5. Xcode中Info.plist文件各个键的作用说明【搜藏】

    Localiztion native development region --- CFBundleDevelopmentRegion 本地化相关,如果⽤户所在地没有相应的语言资源,则用这个key的v ...

  6. 设计模式_Bridge

    形象的例子: —早上碰到MM,要说早上好,晚上碰到MM,要说晚上好:碰到MM穿了件新衣服,要说你的衣服好漂亮哦,碰到MM新做的发型,要说你的头发好漂亮哦.不要问我“早上碰到MM新做了个发型怎么说”这种 ...

  7. log4net使用的一点心得

    关于使用log4net的文章很多,把自己在使用中查到的文章列一下. log4net 可以存在很多地方 比如console,数据库.邮箱.文本等等.我要实现的是 所有的日志都记录到html文件中,可以按 ...

  8. SQL日志文件的作用

    服务器意外关闭造成的损失.服务器意外关闭造成的损失.解决数据一致性问题.数据库时点恢复的问题,这四个常见的问题,SQL Server数据库管理员,可以通过了解数据日志文件,轻松排除故障. 当系统出现故 ...

  9. Linux与Windows的8个不同

    (整理来自网络) 对刚刚接触Linux的人来说,很容易从windows的观念去理解Linux系统.今天扒一扒Win和Linux之间常见的8个区别. 一.Linux终端输入密码不回显字符 用户的密码在L ...

  10. 配置OpenStack以使用LDAP实现身份管理

    本文展示了如何配置 Keystone,以便使用轻量级目录http://www.aliyun.com/zixun/aggregation/34570.html">访问协议( LDAP)服 ...