??xml version="1.0" encoding="utf-8" standalone="yes"?> iostream为内|类型类型对象提供了输入输出支持Q同时也支持文g的输入输出,cȝ设计者可以通过对iostream?
的扩展,来支持自定义cd的输入输出操作? Z么说要扩展才能提供支持呢Q我们来一个示例?%CODE{"cpp"}% #include
<stdio.h> #include class Test { public: Test(int a=0,int b=0) { Test::a=a;
Test::b=b; } int a; int b; }; int main() { Test t(100,50);
printf("%???",t);//不明的输出格式 scanf("%???",t);//不明的输入格式
cout<<t<<endl;//同样不够明确 cin>>t;//同样不够明确
system("pause"); } %ENDCODE%
׃自定义类的特D性,在上面的代码中,无论你用c风格的输入输出,或者是c++的输入输出都不是不明的一个表C,׃c语言没有q算W重载机
ӞDstdio库的不可扩充性,让我们无法让printf()和scanf()支持对自定义cd象的扩充识别Q而c++是可以通过q算W重载机制扩?
iostream库的Qɾpȝ能能够识别自定义cdQ从而让输入输出明确的知道他们该q什么,格式是什么? 在上例中我们之所以用printf与coutq行Ҏ目的是ؓ了告诉大ӞC与C++处理输入输出的根本不同,我们从cq的?
入输出可以很明显看出是函数调用方式,而c++的则是对象模式,cout和cin是ostreamcdistreamcȝ对象? 我们所熟悉的输入输出操作分别是由istream(输入?和ostream(输出?q两个类提供的,Z允许双向的输入/
输出Q由istream和ostreamzZiostreamcR? cȝl承关系见下图: iostream库定义了以下三个标准对象: 输出主要由重载的左移操作W(<<Q来完成Q输入主要由重蝲的右UL作符(>>)完成: q些标准的流对象都有默认的所对应的设备,见下表:1
iostream: istream ?ostream
C++中的iostream库主要包含下图所C的几个头文?
IOSstream ?
fstream
iomainip
ios
iosfwd
iostream
istream
ostream
sstream
streambuf
strstream
上表中的意思表明cin对象的默认输入设备是键盘Qcout对象的默认输备是昄器屏q?
C++对象?/u>
讑֤名称
C中标准设备名
默认含义
cin
键盘
stdin
标准输入
cout
昄器屏q?
stdout
标准输出
cerr
昄器屏q?
stderr
标准错误输出
那么原理上E++有是如何利用cinQcout对象与左Ud右移q算W重载来实现输入输出的呢Q?
下面我们以输Zؓ例,说明其实现原理:
一句输句:cout<<"www.cndev-lab.com"Q,事实上调用的是 ostream& operator<<(ostream &temp,char *ps);q个q算W重载函敎ͼ׃q回的是对象的引用Q引用可以作为左g用,所以当E序中有cMcout<<"www.cndev- lab.com"<<"中国软g开发实验室";q样的语句出现的时候,p够构成连l输出?
׃iostream库不光支持对象的输入输出Q同时也支持文g的输入输出Q所以在详细讲解左移与右U运符重蝲只前Q我? 有必要先Ҏ件的输入输出以及输入输出的控制符有所了解?
׃文g讑֤q不像显C器屏幕与键盘那h标准默认讑֤Q所以它在fstream.h头文件中是没有像cout那样预先定义的全局 对象Q所以我们必自己定义一个该cȝ对象Q我们要以文件作备向文g输出信息(也就是向文g写数?Q那么就应该使用ofstreamcR?
ofstreamcȝ默认构造函数原形ؓQ?%CODE{"cpp"}% ofstream::ofstream(const char *filename,int mode = ios::out,int openprot = filebuf::openprot); %ENDCODE%
其中mode和openprotq两个参数的可选项表见下表Q?
mode 属性表 | |
ios::app | 以追加的方式打开文g |
ios::ate | 文g打开后定位到文g,ios:app包含有此属? |
ios::binary | 以二q制方式打开文gQ缺省的方式是文本方式。两U方式的区别见前? |
ios::in | 文g以输入方式打开 |
ios::out | 文g以输出方式打开 |
ios::trunc | 如果文g存在Q把文g长度设ؓ0 |
openprot 属性表 | |
属? | 含义 |
0 | 普通文Ӟ打开讉K |
1 | 只读文g |
2 | 隐含文g |
4 | pȝ文g |
实例代码如下Q?%CODE{"cpp"}% #include
int main() { ofstream myfile("c:\\1.txt",ios::out|ios::trunc,0); myfile<<"中国软g开发实验室"<<endl<<"|址Q?<<"www.cndev- lab.com"; myfile.close() system("pause"); } %ENDCODE% 文g使用完后可以使用close成员函数关闭文g?
ios::app加模式,在用追加模式的时候同时进行文件状态的判断是一个比较好的习惯?
CZ如下Q?
%CODE{"cpp"}% #include
在定义ifstream和ofstreamcd象的时候,我们也可以不指定文g。以后可以通过成员函数open()昑ּ的把一 个文件连接到一个类对象上?
例如Q?
%CODE{"cpp"}% #include
代码如下Q?%CODE{"cpp"}% #include
我们在简单介l过ofstreamcdifstreamcdQ我们再来看一下fstreamc,fstreamcL? iostreamz而来Qfstreamcd象可以同Ҏ件进行读写操作?
CZ代码如下Q?%CODE{"cpp"}% #include
myfile.open("c:\\1.txt",ios::in,0); if(myfile) { cout<<"文g读错?文g可能丢失!"<<endl; system("pause"); exit(1); } char ch; while(myfile.get(ch)) { cout.put(ch); } myfile.close(); system("pause"); } %ENDCODE% ׃fstreamcd以对文g同时q行d操作Q所以对它的对象q行初始话的时候一定要昑ּ的指定mode和openprot参数?
接下来我们来学习一下串类的基知识Q什么叫串流c?
我们先看看看C++是如何对C风格的字W串进行控制的QC中的字符串其实也是字符数组Q字W数l内的数据在内存中的位置? 排列是连l的Q我们通常?char str[size]或者char *str的方式声明创建C风格字符数组Qؓ了能让字W数l作备ƈ提供输入输出操作QC++引入了ostrstream、istrstream? strstreamq三个类Q要使用他们创徏对象必d含strstream.h头文件?
istrstreamcL从istreamQ输入流c)和strstreambaseQ字W串基c)z? 来,ostrstream是从 ostreamQ输出流c)和strstreambaseQ字W串基c)z而来Qstrstream则是从iostream(输入输出类)和和 strstreambaseQ字W串基c)z而来?
他们的承关pd下图所C?
串流同样不是标准讑֤Q不会有预先定义好的全局对象Q所以不能直接操作,需要通过构造函数创建对象?
cistrstream的构造函数原形如下: %CODE{"cpp"}% istrstream::istrstream(const char *str,int size); %ENDCODE% 参数1表示字符串数l?而参?表示数组大小Q当size?Ӟ表示istrstreamcd象直接连接到由str所指向的内存空间ƈ以\0l尾? 字符丌Ӏ?
下面的示例代码就是利用istrstreamcd建类对象Q制定流输入讑֤为字W串数组Q通过它向一个字W型对象输入数据。代
码如下: %CODE{"cpp"}% #include
我们来一个示例代码: %CODE{"cpp"}% #include
int main() { stringstream ostr("ccc"); ostr.put('d'); ostr.put('e'); ostr<<"fg"; string gstr = ostr.str(); cout<<gstr<<endl;
char a; ostr>>a; cout<<a
system("pause"); } %ENDCODE%
除此而外Qstringstreamcȝ对象我们q常用它q行string与各U内|类型数据之间的转换。示例代码如下:
%CODE{"cpp"}% #include
int main() { stringstream sstr; //--------int转string----------- int a=100; string str; sstr<<a; sstr>>str; cout<<str<<endl; //--------string转char[]-------- sstr.clear();//如果你想通过使用同一stringstream对象实现多种cd的{换,h意在每一ơ{换之后都必须调用clear() 成员函数?string name = "colinguan"; char cname[200]; sstr<<name; sstr>>cname; cout<<cname; system("pause"); } %ENDCODE% 接下来我们来学习一下输?输出的状态标志的相关知识.
int main() { int a; cin>>a; cout<<cin.rdstate()<<endl; if(cin.rdstate() == ios::goodbit) { cout<<"输入数据的类型正,无错误!"<<endl; } if(cin.rdstate() == ios_base::failbit) { cout<<"输入数据cd错误Q非致命错误Q可清除输入~冲区挽回!"<<endl; } system("pause"); } %ENDCODE% 另一U方法则是用下面Q何一个函数来相应的输入/输出状态: %CODE{"cpp"}% bool bad(); bool eof(); bool fail(); bool good(); %ENDCODE%
下例CZQ表C出了上面各成员函数的用法: %CODE{"cpp"}% #include
int main() { int a; cin>>a; cout<<cin.rdstate()<<endl; if(cin.good()) { cout<<"输入数据的类型正,无错误!"<<endl; } if(cin.fail()) { cout<<"输入数据cd错误Q非致命错误Q可清除输入~冲区挽回!"<<endl; } system("pause"); } %ENDCODE% 如果错误发生Q那么流状态既被标Cؓ错误Q你必须清除q些错误状态,以你的E序能正适当地l运行。要清除错误状态,需使用clear()函数? 此函数带一个参敎ͼ它是你将要设为当前状态的标志倹{,只要ios::goodbit作ؓ实参?
CZ代码如下Q?%CODE{"cpp"}% #include
int main() { int a; cin>>a; cout<<cin.rdstate()<<endl; cin.clear(ios::goodbit); cout<<cin.rdstate()<<endl; system("pause"); } %ENDCODE% 通常当我们发现输入有错又需要改正的时候,使用clear()更改标记为正后Q同时也需要用get()成员函数清除输入~冲区,以达到重复输入的? 的?
CZ代码如下Q?%CODE{"cpp"}% #include
int main() { int a; while(1) { cin>>a;
if(cin)//条g可改写ؓcin.fail() { cout<<"输入有错!请重新输?<<endl;
cin.clear(); cin.get(); } else { cout<<a; break; } }
system("pause"); } %ENDCODE% 最后再l出一个对文g错误标记处理的例子Qm固学习,代码如下Q?
%CODE{"cpp"}% #include
int main() { ifstream myfile("c:\\1.txt",ios_base::in,0); if(myfile.fail()) { cout<<"文gdp|或指定文件不存在!"<<endl; } else { char ch; while(myfile.get(ch)) { cout<<ch; } if(myfile.eof()) { cout<<"文g内容已经全部d"<<endl; } while(myfile.get(ch)) { cout<<ch; } } system("pause"); } %ENDCODE%
对这些类的一个对象所做的W一个操作通常是它和一个真正的文g联系hQ也是说打开一个文件。被打开的文件在E序中由一个流对象 (stream object)来表C?(q些cȝ一个实? Q而对q个对象所做的M输入输出操作实际是对该文g所做的操作?/p>
要通过一个流对象打开一个文Ӟ我们使用它的成员函数open()Q?/p>
void open (const char * filename, openmode
mode);
q里filename 是一个字W串Q代表要打开的文件名Qmode 是以下标志符的一个组合:
ios::in | ??而打开 文g |
ios::out | ??而打开 文g |
ios::ate | 初始位置Q文件尾 |
ios::app | 所有输出附加在文g 末尾 |
ios::trunc | 如果文g已存在则? 删除该文?/td> |
ios::binary | 二进制方?/td> |
q些标识W可以被l合使用Q中间以”?#8221;操作W?|)间隔。例如,如果我们惌以二q制方式打开文g”example.bin” 来写入一些数据,我们可以通过以下方式调用成员函数openQ)来实玎ͼ
ofstream file;
ofstream,
ifstream ?fstream所有这些类的成员函数open 都包含了一个默认打开文g的方式,q三个类的默认方式各不相同:
file.open
("example.bin", ios::out | ios::app | ios::binary);
c?/th> | 参数的默认方?/th> |
---|---|
ofstream | ios::out | ios::trunc |
ifstream | ios::in |
fstream | ios::in | ios::out |
只有当函数被调用时没有声明方式参数的情况下,默认值才会被采用。如果函数被调用时声明了M参数Q默认值将被完全改写,而不会与调用参数l合?/p>
׃对类ofstream, ifstream ?fstream 的对象所q行的第一个操作通常都是打开文gQ这些类都有一个构造函数可以直接调用open 函数Qƈ拥有同样的参数。这P我们可以通过以下方式q行与上面同L定义对象和打开文g的操作:
ofstream file ("example.bin", ios::out |
ios::app | ios::binary);
两种打开文g的方式都是正的?/p>
你可以通过调用成员函数is_open()来检查一个文件是否已l被利的打开了:
bool is_open();
它返回一个布?bool)
|为真QtrueQ代表文件已l被利打开Q假( false )则相反?/p>
当文件读写操作完成之后,我们必须文件关闭以使文仉新变为可讉K的。关闭文仉要调用成员函数close()Q它负责缓存中的数据排攑և来ƈ 关闭文g。它的格式很单:
void close ();
q个函数一旦被调用Q原先的?
对象(stream object)可以被用来打开其它的文件了Q这个文件也可以重新被其它的进E?process)所有访问了?/p>
为防止流对象被销毁时q联pȝ打开的文Ӟ析构函数(destructor)会自动调用关闭函数close?/p>
cofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引甌来的。这是Z?fstream 的对象可以用其父类的成员来讉K数据?/p>
一般来_我们用这些类与同控制?console)交互同样的成员函?cin ? cout)来进行输入输出。如下面的例题所C,我们使用重蝲的插入操作符<<Q?/p>
// writing on a text file #include <fiostream.h>int main () { ofstream examplefile (”example.txt”); if (examplefile.is_open()) { examplefile << “This is a line.\n”; examplefile << “This is another line.\n”; examplefile.close(); } return 0; } |
file example.txt This is a line. This is another line. |
从文件中d数据也可以用?cin的用同LҎQ?/p>
// reading a text file #include <iostream.h> #include <fstream.h> #include <stdlib.h>int main () { char buffer[256]; ifstream examplefile (”example.txt”); if (! examplefile.is_open()) { cout << “Error opening file”; exit (1); } while (! examplefile.eof() ) { examplefile.getline (buffer,100); cout << buffer << endl; } return 0; } |
This is a
line. This is another line. |
上面的例子读入一个文本文件的内容Q然后将它打印到屏幕上。注意我们用了一个新的成员函数叫做eof Q它是ifstream 从类 ios 中承过来的Q当到达文g末尾时返回true ?/p>
除了eof()以外Q还有一些验证流的状态的成员函数Q所有都q回bool型返回|Q?/p>
要想重置以上成员函数所查的状态标志,你可以用成员函数clear()Q没有参数?/p>
所有输?输出对?i/o streams objects)都有臛_一个流指针Q?/p>
我们可以通过使用以下成员函数来读出或配置q些指向中d位置的流指针Q?/p>
seekg ( pos_type position );
seekp ( pos_type
position );
使用q个原型Q流指针被改变ؓ指向从文件开始计的一个绝对位|。要求传入的参数cd与函?tellg 和tellp 的返回值类型相同?/p>
seekg ( off_type offset, seekdir direction );
seekp
( off_type offset, seekdir direction );
使用q个原型可以指定由参数direction军_的一个具体的指针开始计的一个位U?offset)。它可以是:
ios::beg | 从流开始位 |计的位移 |
ios::cur | 从流指针? 前位|开始计的位移 |
ios::end | 从流末尾? 开始计的位移 |
?指针 get ?put 的值对文本文g(text file)和二q制文g(binary file)的计方法都是不同的Q因为文本模式的文g中某些特D字W可能被修改。由于这个原因,对以文本文g模式打开的文件L使用seekg ? seekp的第一U原型,而且不要对tellg ?tellp 的返回D行修攏V对二进制文Ӟ你可以Q意用这些函敎ͼ应该不会有Q何意外的行ؓ产生?/p>
以下例子使用q些函数来获得一个二q制文g的大:
// obtaining file size #include <iostream.h> #include <fstream.h>const char * filename = “example.txt”;int main () { long l,m; ifstream file (filename, ios::in|ios::binary); l = file.tellg(); file.seekg (0, ios::end); m = file.tellg(); file.close(); cout << “size of ” << filename; cout << ” is ” << (m-l) << ” bytes.\n”; return 0; } |
size of
example.txt is 40 bytes. |
在二q制文g中,使用<< ?gt;>Q以及函敎ͼ如getlineQ来操作W输入和输出数据Q没有什么实际意义,虽然它们是符合语法的?/p>
?件流包括两个为顺序读写数据特D设计的成员函数Qwrite ?read。第一个函?(write) 是ostream 的一个成员函敎ͼ都是被ofstream所l承。而read 是istream 的一个成员函敎ͼ被ifstream 所l承。类 fstream 的对象同时拥有这两个函数。它们的原型是:
write ( char * buffer, streamsize size );
read (
char * buffer, streamsize size );
q里 buffer 是一块内存的地址Q用来存储或d数据。参数size 是一个整数|表示要从~存QbufferQ中d或写入的字符数?/p>
// reading binary file #include <iostream> #include <fstream.h>const char * filename = “example.txt”;int main () { char * buffer; long size; ifstream file (filename, ios::in|ios::binary|ios::ate); size = file.tellg(); file.seekg (0, ios::beg); buffer = new char [size]; file.read (buffer, size); file.close();cout << “the complete file is in a buffer”;delete[] buffer; return 0; } |
The
complete file is in a buffer |
?我们Ҏ件流q行操作的时候,它们与一个streambuf cd的缓?buffer)联系在一赗这个缓存(bufferQ实际是一块内存空_作ؓ?stream)和物理文件的媒介。例如,对于一个输出流Q? 每次成员函数put (写一个单个字W?被调用,q个字符不是直接被写入该输出所对应的物理文件中的,而是首先被插入到该流的缓存(bufferQ中?/p>
当缓存被排放出来(flush)Ӟ它里面的所有数据或者被写入物理媒质中(如果是一个输出流的话Q,或者简单的被抹?如果是一个输入流的话)? q个q程UCؓ同步(synchronization)Q它会在以下M情况下发生: