600 likes | 755 Views
补充内容 : C++ 的 I/O 流库. 输入 / 输出 (I/O) 是每个程序的基本功能。 输入:是指将数据从外部设备传送到计算机内存的过程; 输出:是指将运算结果从计算机内存传送到外部输出设备的过程。 流的概念: C++ 将数据从一个对象到另一个对象的流动抽象为“流”,流动的方向不同,构成了输入 / 输出流,即 I/O 流。. 主要内容. 流抽象的继承结构 预定义的插入符与提取符 插入符和提取符的重载 磁盘文件的输入和输出 字符串流. 流抽象的继承结构. 1 、流的基本概念.
E N D
补充内容:C++的I/O流库 • 输入/输出(I/O)是每个程序的基本功能。 • 输入:是指将数据从外部设备传送到计算机内存的过程; • 输出:是指将运算结果从计算机内存传送到外部输出设备的过程。 • 流的概念:C++将数据从一个对象到另一个对象的流动抽象为“流”,流动的方向不同,构成了输入/输出流,即I/O流。
主要内容 • 流抽象的继承结构 • 预定义的插入符与提取符 • 插入符和提取符的重载 • 磁盘文件的输入和输出 • 字符串流
流抽象的继承结构 1、流的基本概念 • 在C++中,语言本身并不包含输入和输出功能,但C++标准库提供了一套用于输入和输出的类库。 • 在C++的输入、输出系统中,最核心的对象是流(stream),一个流就是一个字节序列。流的操作包括对流的读和写。 • C++输入输出流的思想:令标准I/O、文件和存储块看上去都一样,只需记住一个接口就可以了。与标准C输入输出库的各种函数相比,输入输出流更容易、更安全、更有效。
ios streambuf istream ostream iostream 流抽象的继承结构(续) 2、C++流的继承结构 • ios:对流状态进行设置,虚基类; • streambuf:提供对数据的缓冲支持; • istream、ostream、iostream:提取与插入;
fstreambase filebuf ifstream ofstream iofstream 流抽象的继承结构(续) 3、文件的继承结构 • fstreambase:公共基类; • filebuf:提供对上述类的缓冲支持; • ifstream、ofstream、iofstream:文件操作;
流抽象的继承结构(续) 4、字符串类 提供处理内部初始化字符序列的操作; istrstream:从序列中取字符; ostrstream:将字符放入序列;
流抽象的继承结构(续) 5、预定义的流 • cin:istream类对象,处理标准输入,即键盘输入; • cout:ostream类对象,处理标准输出,即屏幕输出; • cerr:ostream类对象,处理标准出错信息,提供不带缓冲区的输出; • clog:ostream类对象,处理标准出错信息,提供带缓冲区的输出;
预定义的插入符 1、预定义插入符的格式 ostream& ostream::operator <<(const type& obj); 其中:type为char、int、short、long类型和它们的unsigned和signed类型,以及float、double、long double、char *和void *; 2、说明 • 一般情况下将插入符作用于cout对象; • 输出语句中可以串联多个插入运算符,输出多个数据项;
预定义的插入符(续) • 插入运算符后可以是任意复杂的表达式,系统可自动计算其值并传给插入符; • 指针类型的地址值,默认为十六进制显示,用类型long强制后才可以十进制显示; • 字符指针的地址值的输出格式为:(void *)s或void *(s),此时仍为十六进制格式;
地址值的 十进制 表示方法 地址值的 十六进制 表示方法 字符指 针地址 预定义的插入符(续) #include <iostream.h> #include <string.h> void main() { char *str="Hello"; int a=100; int *pa=&a; cout<<"*pa="<<*pa<<endl; cout<<"&pa="<<&pa<<" or "<<long(&pa)<<endl; cout<<"The string is "<<str<<endl; cout<<"The address is "<<(void *)str <<" or "<<long((void *)str)<<endl; } 例1:分析下列程序的输出结果。 //字符指针
预定义的插入符(续) *pa=100 &pa=0x0065FDEC or 6684144 The string is Hello The address is 0x00426064 or 4350052 输出
控制输出格式 • 控制输出宽度 • 为了调整输出,可以通过在流中放入setw操纵符或调用width成员函数为每个项指定输出宽度。 • 例:使用width控制输出宽度 #include <iostream.H> int main() { double values[] = {1.23,35.36,653.7,4358.24}; for(int i=0;i<4;i++) { cout.width(10); cout << values[i] <<'\n'; } } 输出结果: 1.23 35.36 653.7 4358.24
例:使用*填充 #include <iostream.h> int main() { double values[]={1.23,35.36,653.7,4358.24}; for(int i=0; i<4; i++) { cout.width(10); cout.fill('*'); cout<<values[i]<<'\n'; } } 输出结果: ******1.23 *****35.36 *****653.7 ***4358.24
例: 使用setw指定宽度 #include <iostream.h> #include <iomanip.h> int main() { double values[]={1.23,35.36,653.7,4358.24}; char *names[]={"Zoot","Jimmy","Al","Stan"}; for(int i=0;i<4;i++) cout<<setw(6)<<names[i] <<setw(10)<<values[i] <<endl; } 输出结果: Zoot 1.23 Jimmy 35.36 Al 653.7 Stan 4358.24
例:设置对齐方式 #include <iostream.h> #include <iomanip.h> int main() { double values[]={1.23,35.36,653.7,4358.24}; char *names[]={"Zoot","Jimmy","Al","Stan"}; for(int i=0;i<4;i++) cout<<setiosflags(ios::left) <<setw(6)<<names[i] <<resetiosflags(ios::left) <<setw(10)<<values[i] <<endl; } 输出结果: Zoot 1.23 Jimmy 35.36 Al 653.7 Stan 4358.24
例:控制输出精度 #include <iostream.h> #include <iomanip.h> int main() { double values[]={1.23,35.36,653.7,4358.24}; char *names[]={"Zoot","Jimmy","Al","Stan"}; cout<<setiosflags(ios::scientific); for(int i=0;i<4;i++) cout<<setiosflags(ios::left) <<setw(6)<<names[i] <<resetiosflags(ios::left) <<setw(10)<<setprecision(1) << values[i]<<endl; } 输出结果: Zoot 1.2e+000 Jimmy 3.5e+001 Al 6.5e+002 Stan 4.4e+003
预定义的插入符(续) 3、使用put()输出一个字符 ostream& ostream::put(char c); 4、使用write()输出多个字符 ostream& ostream::write(char *buf,int n); 说明: 这些成员函数既可用于文本流,也可用于二进制流,尤其适用于二进制流;
预定义的插入符(续) #include <iostream.h> void main() { cout<<'a'<<', '<<'b'<<'\n'; cout.put('a').put(', ').put('b').put('\n'); char c1='A',c2='B'; cout.put(c1).put(c2).put('\n'); } 例2:分析下列程序的输出结果。 a,b a,b AB 输 出
预定义的插入符(续) #include <iostream.h> #include <string.h> void PrintString(char *s) { cout.write(s,strlen(s)).put('\n'); cout.write(s,6)<<"\n"; } void main() { char str[]="I love C++"; cout<<"The string is: "<<str<<endl; PrintString(str); PrintString("this is a string"); } 例3:分析下列程序的输出结果。
预定义的插入符(续) The string is: I love C++ I love C++ I love this is a string this i 输出
预定义的提取符 1、预定义提取符的格式 istream& istream::operator >>(type& obj); 其中:type为char、int、short、long类型和它们的unsigned和signed类型,以及float、double、long double、char *; 2、说明 • 一般情况下将提取符作用于cin对象; • 输入语句中可以串联多个提取运算符,每个提取符后为一表达式,该表达式是获得输入值的变量或对象;
预定义的提取符(续) • 提取操作时,空白符(空格、tab键、换行符)只用于字符的分隔符,而本身不作为从输入流中提取的字符; • 提取符可从输入流中读取一个字符串,该字符串是以空白符结束的一个字符序列,由系统自动加上'\0'字符;
预定义的提取符(续) while(cin>>buf) { curLen=strlen(buf); cnt++; if(curLen>maxLen) { maxLen=curLen; largest=buf; } } cout<<endl; cout<<cnt<<endl; cout<<maxLen<<endll; cout<<largest<<endl; } #include <iostream.h> #include <string.h> void main() { const int SIZE=20; char buf[SIZE]; char *largest; int curLen; int maxLen=-1; int cnt=0; cout<<"Input words:"<<endl; 例4:分析下列程序的输出结果。
预定义的提取符(续) Input words: if else return do while continue<ctrl+z> 输 入 6 8 continue 输 出 输入ctrl+z键后,cin>>buf 的值为0,退出while循环;
预定义的提取符(续) 3、使用get()获取一个字符 istream& istream::get(char& c); char istream::get(); 4、使用getline()获取多个字符 istream& istream::getline (char *buf,int Limit,char deline='\n'); 说明: • getline()最多可读取Limit-1个字符;
预定义的提取符(续) • getline()函数结束操作的条件: 从输入流中读取Limit-1个字符后; 从输入流中读取换行符或其他终止符后; 从输出流中读取到文件或输入流结束符后; • getline()通常用来读取一行字符 5、使用read()读取一串字符 istream& istream::read(char *,int);
预定义的提取符(续) #include <iostream.h> void main() { char ch; cout<<"Input: "; while((ch=cin.get())!=EOF) cout.put(ch); cout<<"OK! "<<endl; } 例5:分析下列程序的输出结果。 abc xyz 123<Enter> <ctrl+z> 输入 输出 abc xyz 123<Enter>
预定义的提取符(续) #include <iostream.h> void main() { const int S=12; char buf[S]=""; cout<<"Input…"<<endl; cin.read(buf,S); cout<<endl; cout<<buf<<endl; } 例6:分析下列程序的输出结果。 输入: Input... abcd<Enter> efgh<Enter> ijkl<Enter> Input… abcd efgh ijkl 输 出
插入符和提取符的重载 1、重载为友元函数 ostream& operator<<(ostream&s,const type& p); istream& operator>>(istream&s,type& p); 2、函数调用形式 ostrm<<obj; 等价于 operator <<(ostrm,obj); ostrm<<obj1<<obj2; 等价于 operator <<(operator<<(ostrm,obj1),obj2); istrm>>obj; 等价于 operator >>(istrm,obj); istrm>>obj1>>obj2; 等价于 operator >>(operator>>(istrm,obj1),obj2);
插入符和提取符的重载(续) #include <iostream.h> class Date { public: Date(int y,int m,int d) { Year=y; Month=m; Day=d; } friend ostream& operator << (ostream& stream,Date& date); friend istream& operator >> (istream& stream,Date& date); 例7:分析下列程序的输出结果。
插入符和提取符的重载(续) private: int Year,Month,Day; }; ostream& operator <<(ostream& stream,Date& date) { stream<<date.Year<<"/"<<date.Month<<"/" <<date.Day<<endl; return stream; } istream& operator >>(istream& stream,Date& date) { stream>>date.Year>>date.Month>>date.Day; return stream; } void main()
插入符和提取符的重载(续) { Date CDate(1999,10,22); cout<<"Current date: "<<CDate<<endl; cout<<"Enter new date: "; cin>>CDate; cout<<"New date: "<<CDate<<endl; } Current date: 1999/10/22 Enter new date: 2001 10 22 New date: 2001/10/22 输 出
磁盘文件的打开和关闭 1、打开文件 • void fstream::open(const char *fname, int mode,int= filebuf::openprot); • fstream::fstream(const char *fname, int mode,int= filebuf::openprot); • void ofstream::open(const char *fname, int mode=ios::out,int= filebuf::openprot); • ofstream::ofstream(const char *fname, int mode=ios::out,int= filebuf::openprot); • void ifstream::open(const char *fname, int mode=ios::in,int= filebuf::openprot); • ifstream::ifstream(const char *fname, int mode=ios::in,int= filebuf::openprot);
磁盘文件的打开和关闭(续) 说明: 第一个参数是指向要打开的文件名字串,第二个和第三个参数说明文件如何被打开。 参数mode:打开方式 ios::ate —— 如果文件存在,输出内容加在末尾 ios::in —— 具有输入能力(ifstream默认) ios::out —— 具有输出能力(ofstream默认) ios::trunc —— 如文件存在,清除文件内容(默认) ios::nocreate —— 如文件不存在,返回错误 ios::noreplace —— 如文件存在,返回错误 ios::binary —— 以二进制方式打开文件
磁盘文件的打开和关闭(续) 参数prot:文件保护方式 filebuf::openprot ——兼容共享方式 filebuf::sh_none ——独占,不共享 filebuf::sh_read ——允许读共享 filebuf::sh_write ——允许写共享
磁盘文件的打开和关闭(续) 2、关闭文件 void fstream::close(); void ofstream::close(); void ifstream::close();
磁盘文件的打开和关闭(续) #include <fstream.h> void main() { ofstream ostrm; ostrm.open("f1.dat"); ostrm<<120<<endl; ostrm<<310.85<<endl; ostrm.close(); ifstream istrm("f1.dat"); int n; double d; istrm>>n>>d; cout<<n<<", "<<d<<endl; istrm.close(); } 例8:分析下列程序的输出结果。 输出: 120,310.85
文本文件的读写操作 #include <iostream.h> #include <fstream.h> #include <stdlib.h> void main() { fstream outfile; outfile.open("f2.dat",ios::out); if(!outfile) { cout<<"f2.dat can't open. "<<endl; abort(); } outfile<<"this is a program. "<<endl; outfile.close(); } 例9:将文本写入指定的文件。 退出程序
文本文件的读写操作(续) #include <iostream.h> #include <fstream.h> #include <stdlib.h> void main() { fstream infile; infile.open("f2.dat",ios::in); if(!infile) { cout<<"f2.dat can't open. "<<endl; abort(); } char s[80]; while(!infile.eof()) { infile.getline(s,sizeof(s)); cout<<s<<endl; } infile.close(); } 例10:从文本文件中读出信息。
文本文件的读写操作(续) #include <iostream.h> #include <fstream.h> #include <stdlib.h> #include <string.h> void main() { fstream outfile,infile; outfile.open("f3.dat",ios::out); if(!outfile) { cout<<"f3.dat can't open. "<<endl; abort(); } char str[]="this is a c++ program. "; 例11:使用get()和put()函数读写文件。
文本文件的读写操作(续) for(int i=0;i<strlen(str);i++) outfile.put(str[i]); outfile.close(); infile.open("f3.dat",ios::in); if(!infile) { cout<<"f3.dat can't open. "<<endl; abort(); } char ch; while(infile.get(ch)) cout<<ch; cout<<endl; infile.close(); } 输出: this is a c++ program.
文本文件的读写操作(续) #include <iostream.h> #include <fstream.h> #include <stdlib.h> void main() { fstream outfile,infile; infile.open("f2.dat",ios::in); if(!infile) { cout<<"f2.dat can't open. "<<endl; abort(); } outfile.open("f4.dat",ios::out); if(!outfile) 例12:将一文件内容拷贝到另一文件。
文本文件的读写操作(续) { cout<<"f4.dat can't open. "<<endl; abort(); } char ch; while(infile.get(ch)) outfile.put(ch); infile.close(); outfile.close(); }
二进制文件的读写操作 #include <iostream.h> #include <fstream.h> #include <stdlib.h> struct person { char name[20]; double height; int age; } struct person people[4]={"Wang",1.65,25, "Zhang", 1.72,24, "Li",1.89,21, "Huang",1.70,22}; void main() { fstream outfile,infile; 例13:对一二进制文件进行读写操作。
二进制文件的读写操作(续) outfile.open("f5.dat",ios::out|ios::binary); if(!outfile) { cout<<"f5.dat can't open. "<<endl; abort(); } for(int i=0;i<4;i++) outfile.write((char *)&people[i], sizeof(people[i])); outfile.close(); infile.open("f5.dat",ios::in|ios::binary); if(!infile) { cout<<"f5.dat can't open. "<<endl; abort();
二进制文件的读写操作(续) } for(int i=0;i<4;i++) { outfile.read((char *)&people[i], sizeof(people[i])); cout<<people[i].name<<"\t" <<people[i].height<<"\t" <<people[i].age<<endl; } infile.close(); } Wang 1.65 25 Zhang 1.72 24 Li 1.69 21 Huang 1.7 22 输 出
随机访问数据文件 1、读文件指针 istream& istream::seekg(streampos); istream& istream::seekg(streamoff,ios::seek_dir); streampos istream::tellg(); streampos为long型; Streamoff为移动的字节数,正数表示正向,负数是反向。 seek_dir的值: cur=1,相对于当前读指针指定的位置; beg=0,相对于流的开始位置; end=2,相对于流的结尾位置;
随机访问数据文件(续) 2、写文件指针 ostream& ostream::seekp(streampos); ostream& ostream::seekp(streamoff,ios::seek_dir); streampos ostream::tellp();
随机访问数据文件(续) #include <iostream.h> #include <fstream.h> #include <stdlib.h> void main() { struct student { char name[20]; long number; double totalscore; }struct stu[5]={"Ma",97001,85.72, "Li",97002,92.62, "Hu",97003,89.25, "Yan",97004,90.84, "Lu",97005,80.92}; 例14:分析下列程序的输出结果。