注册 登录
编程论坛 C++教室

IO流与文件流的缓冲问题

Arcticanimal 发布于 2007-03-18 13:17, 2293 次点击
//代码没多大意义,仅举个例子
#include<iostream.h>
#include<fstream.h>
#include<stdio.h>
#include<conio.h>
#include<process.h>
int main()
{ ///////////////////////以下可以略去不看////////////////////////////////////////
system("if exist C:\\测试文件夹 echo 已经存在测试文件夹,正在清空...");
system("if exist C:\\测试文件夹 del C:\\测试文件夹 /q");
system("if not exist C:\\测试文件夹 echo 不存在 \"C:\\测试文件夹 正在建立文件夹...\"");
system("if exist C:\\测试文件夹 rd C:\\测试文件夹");

if(!system("md C:\\测试文件夹"))
printf("测试文件夹建立成功!文件路径:C:\\测试文件夹\\test.bin \n");
//////////////////////////////////////////////////////////////////////////////
ofstream fileo("C:\\测试文件夹\\test.bin",ios::binary);
char input='\0'; //从此处改变 char buffer[2]={'\0','\0'}
printf("写入文件:>"); // printf("写入文件:>");
while(input!='\r') // while(buffer[0]!='\r')
{ input=getche(); // { input=getche();
fileo<<input; // buffer[1]=buffer[0];
} // buffer[0]=input;
// if(buffer[0]!='\b')
// fileo<<buffer[1];
// } //试图在文件里面过滤掉backspace符

printf("写入完成!\n");
fileo.close();
printf("文件关闭!\n");
ifstream filei("C:\\测试文件夹\\test.bin",ios::binary);
char info[100];
for(int j=0;j<100;j++)
info[j]='\0';
filei.read(info,99);
cout<<"读取完毕,输出:>"<<info<<endl; //改变代码后在“读取完毕,输出”后没有输出任何东西!!!
filei.close();
return 0;
}
直接的代码编译后能输出输入的字符
另一个问题:如果将printf函数用IO流的cin代替,结果会导致cout输出的顺序混乱
已经很多次碰到这个问题了,猜想是跟IO流与文件流的缓冲有关,但还是不清楚
恳请那位大虾详细指教!

[此贴子已经被作者于2007-3-18 13:38:39编辑过]

21 回复
#2
Arcticanimal2007-03-19 21:19
没有人能够说说自己的看法吗
#3
dlcdavid2007-03-20 20:03
#include<iostream.h>
#include<fstream.h>
#include<stdio.h>
#include<conio.h>
#include<process.h>
int main()
{ ///////////////////////以下可以略去不看////////////////////////////////////////
system("if exist C:\\测试文件夹 echo 已经存在测试文件夹,正在清空...");
system("if exist C:\\测试文件夹 del C:\\测试文件夹 /q");
system("if not exist C:\\测试文件夹 echo 不存在 \"C:\\测试文件夹 正在建立文件夹...\"");
system("if exist C:\\测试文件夹 rd C:\\测试文件夹");

if(!system("md C:\\测试文件夹"))
printf("测试文件夹建立成功!文件路径:C:\\测试文件夹\\test.bin \n");
//////////////////////////////////////////////////////////////////////////////
ofstream fileo("C:\\测试文件夹\\test.bin",ios::binary);
char input='\0';
printf("写入文件:>");
while(input!='\r')
{
input=getche();
if(input!=' ')
fileo<<input;
} //试图在文件里面过滤掉backspace符
printf("写入完成!\n");
fileo.close();
printf("文件关闭!\n");
ifstream filei("C:\\测试文件夹\\test.bin",ios::binary);
char info[100];
for(int j=0;j<100;j++)
info[j]='\0';
filei.read(info,99);
cout<<"读取完毕,输出:>"<<info<<endl; //改变代码后在“读取完毕,输出”后没有输出任何东西!!!
filei.close();
return 0;
}

这样就行了
#4
Arcticanimal2007-03-20 20:13
谢谢楼上的
我是想问为什么两种代码会导致不同的输出结果
ofstream fileo("C:\\测试文件夹\\test.bin",ios::binary);
char input='\0'; //从此处改变 char buffer[2]={'\0','\0'}
printf("写入文件:>"); // printf("写入文件:>");
while(input!='\r') // while(buffer[0]!='\r')
{ input=getche(); // { input=getche();
fileo<<input; // buffer[1]=buffer[0];
} // buffer[0]=input;
// if(buffer[0]!='\b')
// fileo<<buffer[1];
// } //试图在文件里面过滤掉backspace符
那位大侠能解释一下输出缓冲与文件流缓冲的关系
#5
dlcdavid2007-03-20 20:31
回复:(Arcticanimal)IO流与文件流的缓冲问题
//来调试一下就知道了.输入12 34 56
//...
while(buffer[0]!='\r')
{ //这个地方监视一轮就能出现问题
input=getche(); //input==1.
buffer[1]=buffer[0]; //buffer[1]=='\0',buffer[0]=='\0',input==1.
buffer[0]=input; //buffer[1]=='\0',buffer[0]=='1',input==1.
if(buffer[0]!=' ') //buffer[0]=='1'通过
fileo<<buffer[1]; //问题在这里,,buffer[1]=='\0'
} //试图在文件里面过滤掉backspace符
//文件里有\0... 后面的已经没必要知道了,但肯定不是\0 1 2 3 4 ...
printf("写入完成!\n");
fileo.close();
printf("文件关闭!\n");
ifstream filei("C:\\测试文件夹\\test.bin",ios::binary);
char info[100];
for(int j=0;j<100;j++)
info[j]='\0';
filei.read(info,99);//read()读取到第一个字符时就遇到\0.也就退出了,
//所以info是空的,当然就没有输出

cout<<"读取完毕,输出:>"<<info<<endl; //改变代码后在“读取完毕,输出”后没有输出任何东西!!!
filei.close();
return 0;
}

[此贴子已经被作者于2007-3-20 21:11:37编辑过]

#6
dlcdavid2007-03-20 20:32

呵呵,,是个小问题,希望lz以后仔细一点

#7
Arcticanimal2007-03-20 21:15
哦!!!恍然大悟 谢了
还问一个问题,为什么把 printf换成cout 后输出的顺序会变化?
#8
yuyunliuhen2007-03-20 21:49

cout是有缓冲的.cout要endl才能刷新缓存区,printf是即时刷新
看看下面这个程序:
#include<iostream>
#include "stdio.h"
using namespace std;
main()
{
int iSize=1;
cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<"\n";
printf("printf iSize=%d \n",iSize);
return 0;
}
这个先输出printf这个.再把它改一下加个cout.flush();
#include <iostream>
#include "stdio.h"
using namespace std;
main()
{
int iSize=1;
cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<"\n";
cout.flush(); //
printf("printf iSize=%d \n",iSize);
return 0;
}
那么,这样输出顺序就换过来了

cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<"\n"; ->cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<endl; 也可以

[此贴子已经被作者于2007-3-20 22:02:29编辑过]

#9
dlcdavid2007-03-20 22:32
不知道楼上的想表达什么?
#10
yuyunliuhen2007-03-20 22:41

为什么 printf换成cout 后输出的顺序会变化?


cout是有缓冲的.cout要endl,flush()才或者能刷新缓存区,printf是即时刷新;
当两者混用的时候,cout刷新缓存区需要一定的时间,所以会比printf后输出

[此贴子已经被作者于2007-3-20 22:44:01编辑过]

#11
dlcdavid2007-03-20 22:48
以下是引用yuyunliuhen在2007-3-20 21:49:15的发言:

cout是有缓冲的.cout要endl才能刷新缓存区,printf是即时刷新


没考证,如果是这样,那应该是
cout<<"写入文件:>";//输出缓冲区刷新,"写入文件:>"暂时未输出到设备
getche() //不经过缓冲区,所以缓冲区刷新,"写入文件:>"暂时未输出到设备
cout<<"写入完成!\n";//先刷新缓冲区,"写入文件:>"输出到设备
//然后将"写入完成!\n";写入到缓冲区

以上的话没考证,是猜想,有知道的大虾说一下

[此贴子已经被作者于2007-3-20 22:59:49编辑过]

#12
dlcdavid2007-03-20 22:49
以下是引用yuyunliuhen在2007-3-20 22:41:02的发言:

为什么 printf换成cout 后输出的顺序会变化?


cout是有缓冲的.cout要endl,flush()才或者能刷新缓存区,printf是即时刷新;
当两者混用的时候,cout刷新缓存区需要一定的时间,所以会比printf后输出


你上面两个程序的输出是一样的

[此贴子已经被作者于2007-3-20 22:50:01编辑过]

#13
yuyunliuhen2007-03-20 23:07
不会呀,把#include<iostream.h >换成
#include<iostream >
using namespace std;
怎么结果就变了呢?


#include<iostream.h >
#include "stdio.h"
main()
{
int iSize=1;
cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<"\n";
printf("printf iSize=%d \n",iSize);
return 0;
}

----------------------------------------------------
#include <iostream.h>
#include "stdio.h"
main()
{
int iSize=1;
cout<<"cout iSize="<<++iSize+(++iSize)*iSize++<<"\n";
cout.flush();
printf("printf iSize=%d \n",iSize);
return 0;
}

[此贴子已经被作者于2007-3-20 23:11:18编辑过]

#14
dlcdavid2007-03-20 23:10
以下是引用dlcdavid在2007-3-20 22:48:23的发言:

没考证,如果是这样,那应该是
cout<<"写入文件:>";//输出缓冲区刷新,"写入文件:>"暂时未输出到设备
getche() //不经过缓冲区,所以缓冲区刷新,"写入文件:>"暂时未输出到设备
cout<<"写入完成!\n";//先刷新缓冲区,"写入文件:>"输出到设备
//然后将"写入完成!\n";写入到缓冲区

以上的话没考证,是猜想,有知道的大虾说一下


缓冲区刷新条件:
1程序正常结束.(程序崩溃不刷新)
2缓冲区满,将在写下个值前刷新
3用操作符刷新,如endl.
4用unitbuf设置流内部状态.从而清空缓冲区
5如果输入输出流关联,在读输入流时刷新其关联输出缓冲区(cin.tie(&cout)可将cin与cout关联)
(一个ostream对象每次只能与一个istream对象绑在一起,传递cin.tie(0)取消捆绑)

------------------------------------------------------------------------------------------------------

以下是引用yuyunliuhen在2007-3-20 22:41:02的发言:

cout刷新缓存区需要一定的时间,所以会比printf后输出

理解错了,
在程序执行时cout的缓冲区一直没刷新

执行到printf的时候,他的输出立即显示到了设备上
退出程序的时候return才清空了cout的缓冲区
所以cout的输出才会在printf的后面

[此贴子已经被作者于2007-3-20 23:18:51编辑过]

#15
wfpb2007-03-20 23:11
如yuyunliuhen所说,是缓冲流没有flush的原因
#16
dlcdavid2007-03-20 23:16
以下是引用yuyunliuhen在2007-3-20 22:41:02的发言:

cout刷新缓存区需要一定的时间,所以会比printf后输出

理解错了,
在程序执行时cout的缓冲区一直没刷新

执行到printf的时候,他的输出立即显示到了设备上
退出程序的时候return才清空了cout的缓冲区
所以cout的输出才会在printf的后面

#17
song42007-03-20 23:22
#18
wfpb2007-03-20 23:31

13楼:我以前也碰到过,但是似乎是没打vc6sp6补丁之前,现在试了下,两个程序都是一样的输出。

#19
yuyunliuhen2007-03-20 23:44
还是一样的输出吗,可是在我的机器上为什么会不同呢?我的版本是VC++ 6.0 SP6.大企龙卷风集成安装版的.
#20
yuyunliuhen2007-03-20 23:52
以下是引用dlcdavid在2007-3-20 23:16:23的发言:


在程序执行时cout的缓冲区一直没刷新

执行到printf的时候,他的输出立即显示到了设备上
退出程序的时候return才清空了cout的缓冲区
所以cout的输出才会在printf的后面

cout 这是一个流对象,没有刷新的功能,而是endl 有这个功能。它不但现了换行操作,而且还对输出缓冲区进行刷新。
在执行输出操作之后,数据并非立刻传到输出设备,而是先进入一个缓冲区,当适宜的时机(也就是你说的在退出程序的时候return吗?)后再由缓冲区传入,也可以通过操纵符flush进行强制刷新,这样当程序执行到flash之前,有可能前面的字符串数据还在缓冲区中而不是显示在屏幕上,但执行flash之后,程序会强制把缓冲区的数据全部搬运到输出设备并将其清空。而操纵符endl相当于<< "\n" << flush的简写版本,它先输出一个换行符,再实现缓冲区的刷新。
PRINR是即时刷新..
这样理解也可以吧?

#21
song42007-03-21 11:00

C++对的
C忘了,如果C里面没有刷新操作,那你就对了

#22
Arcticanimal2007-03-22 13:08
谢谢各位大虾和斑竹的讨论!,真是大有收获
1