Presentation is loading. Please wait.

Presentation is loading. Please wait.

第8章 C++输入输出类层次 ffh.

Similar presentations


Presentation on theme: "第8章 C++输入输出类层次 ffh."— Presentation transcript:

1 第8章 C++输入输出类层次 ffh

2 目录 8.1 概述 8.2 格式化输入/输出 8.3 重载流的插入符和提取符 8.4 常用成员函数I/O 8.5 流的错误处理
8.1 概述 8.2 格式化输入/输出 8.3 重载流的插入符和提取符 8.4 常用成员函数I/O 8.5 流的错误处理 8.6 文件流操作 8.7 字符串流

3 8.1 概述 输入输出操作在C++语言中没有定义,但提供了一个I/O 流库 C++输入输出类核心是:流!
一个流就是一个字节序列,如果流向程序,这个流就称为输入流: 如果流出程序,则称为输出流。 如果输入流来源于键盘,表明你的程序要从键盘获取输入;如果输 入流来源于一个文件,表明程序要从那个文件获取输入。类似地 ,输出流可以发送给屏幕或文件。 主要包括: 标准流类:处理与标准输入设备(键盘)和输出设备(显示器) 关联的数据流

4 8.1 概述 文件 文件流类:处理与磁盘文件关联的数据流 字符串流类:利用内存中的字符数组处理数据的输入输出 异常类等:处理异常错误
其他:网络流等 文件 文件是指存储在外部介质上具有名称的数据集合

5 8.1.1 标准输入输出层次体系 Ios_base basic_ios basic_istream basic_ostream
basic_ifstream basic_istringstream basic_iostream basic_ostringstream basic_ofstream basic_stringstream basic_fstream

6 8.1.1 标准输入输出层次体系 Ios_base:流的抽象基类,描述了流的基本性质,不考虑流的字符集
basic_ios:流的抽象基类,描述了流的基本性质,考虑流的字符集 basic_istream:描述流中读写和移动数据的方法;重载<<,>> basic_ostream basic_ifstream:对文件进行读取 basic_ofstream basic_fstream:从fstreambase类和iostream类中派生,可对文件进 行插入和提取操作 basic_istringstream basic_iostream basic_ostringstream basic_stringstream

7 8.1.2 输入输出库中的缓冲类层次 C++输入输出类结构,如图 Input buff 键盘 显示器 处理 Output buff abcd
uvwxyz 驱动程序

8 系统预定义4个流类的对象: 在使用下述类时,总要包含iostream.h文件:
cin:它是istream类的对象,用来处理标准输入,即键盘输入 cout:它是ostream类的对象,用来处理标准输出,即屏幕输出 cerr:它是ostream类的对象,用来处理标准出错信息,它提供不 带缓冲区的输出 clog:它是ostream类的对象,用来处理标准出错信息,它提供带 缓冲区的输出

9 支持文件的流类

10 8.2 格式化输入/输出 使用ios类的成员函数进行格式控制 使用控制符进行格式控制

11 使用ios类的成员函数进行格式控制 用ios类的成员函数来对输入/输出的格式进行控制,如格 式标志字、域宽、充填字符及输出精度等。 1.使用ios类的成员函数设置标志字 ios类中声明了一个数据成员,用于记录当前流的格式化状态,这个 数据成员称为标志字。标志字的每一位用于记录一种格式。 使用标志常量或直接用对应的十六进制值设置输入输出流的格式。 下表列出了主要标志常量名及其意义。

12 使用ios类的成员函数进行格式控制

13 使用ios类的成员函数进行格式控制

14 8.2.1 使用ios类的成员函数进行格式控制 Ios的几个直接操作标志字的公有成员函数:
(1) long flags():该函数用来返回标志字。 (2) long flags(long):该函数使用参数值来更新标志字,并返回更新 前的标志字。 (3) long setf(long setbits,long field):该函数用来将field所指定的标 志位清零,将setbits为1的标志位置为1,并返回设置前的标志字 。 (4) long setf(long):该函数用来设置参数所指定的那些标志位,并返 回更新前的标志字。 (5)long unsetf(long) :该函数用来清除参数所指定的那些标志位, 并返回更新前的标志字。

15 8.2.1 使用ios类的成员函数进行格式控制 例8.1:以几种不同的格式输出同一浮点数,示例如何使用成 员函数来操作标志字。
#include <iostream> using namespace std; int main( ) { double a=12.34; cout<<"a="<<a<<endl; cout.setf(ios::showpos); cout.setf(0x0100); cout<<"a="<<a<<endl; cout.setf(0x1000); return 0; } 结果: a=12.34 a=+12.34 a= e+001

16 使用ios类的成员函数进行格式控制 例8.2:以几种不同的进制输出同一整数。示例ios定义的公有静态符 号常量的作用。 #include <iostream> using namespace std; int main( ) { double a=12; cout.setf(ios::showbase); cout<<"以十进制输出12为:"; cout.setf(ios::dec,ios::basefield); cout<<12<<endl; cout<<“以八进制输出12为:“; cout.setf(ios::oct,ios::basefield); cout<<12<<endl; cout<<"以十六进制输出12为:"; cout.setf(ios::hex,ios::basefield); cout<<12<<endl; return 0; }

17 输出结果 以十进制输出12为:12 以八进制输出12为:014 以十六进制输出12为:0xc

18 8.2.1 使用ios类的成员函数进行格式控制 2.使用ios类的成员函数设置域宽、充填字符及输出精度
(1) 设置输出数据所占宽度的函数: int width() 该函数用来返回当前输出的数据宽度。 int width(int) 该函数用来设置当前输出的数据宽度,并返回更新之前的宽度值。 (2) 填充当前宽度内的填充字符函数 char fill() 该函数用来返回当前所使用的填充字符。 charfill(char) 该函数用来设置当前填充字符为参数所表示的字符,并返回更新前 的填充字符。

19 使用ios类的成员函数进行格式控制 (3) 设置浮点数输出精度函数 int precision() 该函数用来返回当前浮点数的有效数字的个数。 int precision(int) 该函数用来设置当前浮点数输出时的有效数字个数为该函数的参数 值,并返回更新前的值。

20 使用ios类的成员函数进行格式控制 例8.3:示例如何使用ios类的成员函数设置域宽、充填字符及输出精 度。 #include <iostream> #include <string> using namespace std; int main() { double values[] = {1.23,35.36,653.7, }; char *names[] = {"aaaaaaa", "bbbb", "ccccc", "dddddd"};

21 运行结果: for (int i=0;i<4;i++) { cout.setf(ios::left);//设置左对齐
cout.fill('*');//充填字符为* cout.width(10);//设置域宽为10 cout.precision(5);//输出精度为5 cout<<names[i] <<", ”<<values[i]<< endl; } return 0; } 运行结果: aaaaaaa***, 1.23 bbbb******, 35.36 ccccc*****, 653.7 dddddd****,

22 使用控制符进行格式控制

23 使用控制符进行格式控制

24 使用控制符进行格式控制 例8.4 使用控制符进行格式控制,完成例8.3同样的功能。 #include <iostream> #include <iomanip> using namespace std; int main() { double values[] = {1.23,35.36,653.7, }; char *names[] = {"aaaaaaa", "bbbb", "ccccc", "dddddd"}; for (int i=0;i<4;i++) {cout<<setiosflags(ios::left) <<setfill('*')<<setw(10)<< names[i]<<", "; cout<<setprecision(5)<< values[i]<< endl; } return 0; }

25 8.3 重载流的插入符和提取符 运算符重载有两种形式:重载为成员函数或者是重载为友 元函数。由于重载插入符和提取符时,其左边的参数是流 ,而右边的参数是类的对象,因此,插入符和提取符只能 重载为友元函数。 插入符重载的一般格式如下: ostream& operator<<(ostream& s, classa& a) { <函数体> return s; }

26 8.3 重载流的插入符和提取符 例8.5:重载流的插入符和提取符,完成复数类的功能。 #include <iostream> using namespace std; class Complex {public: Complex(double r=0,double i=0); friend Complex operator + (Complex c1,Complex c2);//重载加 friend Complex operator - (Complex c1,Complex c2);//二元减 friend istream& operator>>(istream& s, Complex& c); friend ostream& operator<<(ostream& s, Complex& c); private: double real,imag; };

27 8.3 重载流的插入符和提取符 Complex ::Complex(double r,double i) { real=r;imag=i;} Complex operator+(Complex c1, Complex c2) { Complex temp; temp.real=c1.real + c2.real; temp.imag=c1.imag + c2.imag; return temp; } Complex operator-(Complex c1, Complex c2) temp.real=c1.real - c2.real; temp.imag=c1.imag - c2.imag; return temp; }

28 8.3 重载流的插入符和提取符 istream& operator>>(istream& s, Complex& c) { s>>c.real>>c.imag; return s; } ostream& operator<<(ostream& s, Complex& c) { s<<'('<<c.real<<','<<c.imag<<')'<<endl; return s; } int main() { Complex c1,c2; cin>>c1>>c2; Complex c; cout<<“c1=”<<c1; cout<<"c2="<<c2; c=c1+c2; //c=operator+(c1,c2); cout<<"c1+c2="<<c; c=c1-c2; //c=operator-(c1,c2); cout<<"c1-c2="<<c; return 0; }

29 8.4 常用成员函数I/O 输入流的常用成员函数 输出流的常用成员函数

30 8.4.1 输入流的常用成员函数 1.read()函数 istream& read(char*pch,int nCount);
输入流的常用成员函数 1.read()函数 istream& read(char*pch,int nCount); 将指定的nCount个字符输入到内存中的字符数组pch。如果读取的字 符数量少于指定的数量,就会设置failbit错误位。 void main( ) {   const int S = 80;     char buf[S] = " ";     cout << "Input…\n";     cin.read(buf, S);     cout << endl;     cout << buf << endl; }

31 Ans: 执行该程序显示如下信息: Input… abcd <ctrl+z> 输出如下:

32 8.4.1 输入流的常用成员函数 2.get()函数 该函数有3种主要形式:  istream& int get()
输入流的常用成员函数 2.get()函数 该函数有3种主要形式:  istream& int get() 从指定的输入流中输入一个字符(包括空白字符),并返回该字符作为 函数调用的值;遇到输入流中的文件结束符时,此get函数返回 EOF。 istream& int get(char& rch ) 从输入流读取一个字符(包括空白字符),并将其存储rch。当遇到文 件结束符时,此get函数返回0,否则返回对istream对象的引用, 并用该引用再次调用get成员函数。 istream& int get(char& pch, int nCount,char delim=’\n’) 从输入流中读取字符。函数要么在读取到nCount-1个字符后终止, 要么在读取到指定的分隔符delim时终止。

33 例: 从键盘输入 abc xyz 123 void main( ) { char ch; cout << "Input: ";
    while((ch = cin.get( ))! = EOF) // EOF = -1,包含在 iostream        cout.put(ch);     cout << "ok!"; } Ans: Input: abc xyz 123 ^z Ok!

34 8.4.1 输入流的常用成员函数 3.getline() 4.gcount()函数
输入流的常用成员函数 3.getline() 与带3个参数的get成员函数类似,它读取一行字符串后在字符数组 末尾加入’\0’。不同的是,getline要从输入流中删除分隔符(即 读取并删除它),而不是把它存放在数组中。 4.gcount()函数 无参函数,统计最后一次输入操作读取的字符数。 例:求每行字符个数,最长行字符个数,多少行 const int SIZE=80; void main( ) {    int lcnt = 0, lmax=-1; // 行数,最长行的输入字符个数     char buf[SIZE];    cout << "Input…\n";

35     while(cin.getline(buf, SIZE))
    {   int count = cin.gcount( ); // 输入字符的个数         lcnt++;         if(count > lmax) lmax = count;             cout << "Line # " << lcnt << "\t" << "chars read: " << count << endl;         cout.write(buf, count).put('\n').put('\n');     }      cout << endl;      cout << "Total line: " << lcnt << endl;      cout << "Longest line: " << lmax << endl; }

36 Ans: Input… this is a string. Line #1 chars read:18 you are a student.
the four seacons of the year. Line #3 chars read:30 the four seasons of the year. change to a N.332 bus. Line #4 chars read:25 输入<ctrl+z>后,输出: Total line:4 Longest line:30

37 8.4.1 输入流的常用成员函数 5.ignore()函数 该函数原型为:
输入流的常用成员函数 5.ignore()函数 该函数原型为: istream& ignore(int n=1,int t=EOF); 遇到指定的终止字符t时提前结束或跳过输入流中n个字符结束(此时 跳过包括终止字符内的若干个字符)。终止字符仍停留在输入流中 。

38 8.4.1 输入流的常用成员函数 6. putback()函数 7. peek()函数 该函数原型为:
输入流的常用成员函数 6. putback()函数 该函数原型为: istream& putback(char ch); 把上一次从输入流中通过get(或getline)取得的字符再放回该输入流 中。对于应用程序需要扫描输入流以查找以特定字符开头的字段 来说,这是非常有用的。当输入一个字符时,应用程序把该字符 放回输入流,以保证输入的数据中包含该字符。 7. peek()函数 无参函数,返回输入流的下一个字符,但并不将其从输入流中删除 。其作用是观测该字符,字符指针仍停留在原来位置上。

39 例 peek( )查找ab连续组合 #include <iostream.h> void main( )
{   int ch , cnt=0;     cout << "Input…\n";     while((ch = cin.get( )) != EOF) {  if(ch == 'a' && cin.peek( ) == 'b‘) cnt++;    }     cout << endl;    cout << cnt << endl; } 当输入流如下所示: mabyababcabcdab <ctrl+z> 6

40 8.4.2 输出流的常用成员函数 1.write()函数 ostream& write(const *str, int n);
输出流的常用成员函数 1.write()函数 ostream& write(const *str, int n); 将字符串送到输出流。例如: cout.write("string", strlen("string")); #include <string> void PrintString(char *s) {   cout.write(s, strlen(s)).put('\n');    cout.write(s, 6) << "\n“; }

41 例: 函数write( ) void main( ) { char str[ ] = "I love C++“;
    cout << "The string is: " << str << endl;     PrintString(str);    PrintString("this is a string"); } Ans: The string is: I love C++ I love C++ I love this is a str this i

42 8.4.2 输出流的常用成员函数 2. put()函数 ostream& put(char ch ); 输出一个字符。
输出流的常用成员函数 2. put()函数 ostream& put(char ch ); 输出一个字符。 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’); } Ans: a, b AB

43 8.4.2 输出流的常用成员函数 例8.6:从输入的串中分离数字串,示例常用成员函数I/O
输出流的常用成员函数 例8.6:从输入的串中分离数字串,示例常用成员函数I/O #include <iostream> using namespace std; int main() { char str[10]; int i=0; cout<<"输入一个字符串(最多9个字符)"; cin.get(str,10,'!');//输入一个字符串 char c=str[i]; cout<<"数字串为:"<<endl;

44 输出流的常用成员函数 while (i<cin.gcount()) { if (isdigit(c))//输出数字串 cout.put(c); if(isdigit(c)&&!isdigit(str[i+1])) cout<<endl; i=i+1; c=str[i]; } return 0; }

45 8.5 流错误的处理 I/0流的错误状态字 I/0流的状态函数

46 在对流进行操作时,可能会发生错误 必须有一种能够检测到错误状态的机制和清除错误的方法 通过几种方法都可以检测出错误,并查明其错误性质,然 后调用clear( )函数清除错误状态,可以使得流能够恢复 处理。

47 8.5.1 I/0流的错误状态字 ios类定义了一个数据成员,用它来记录各种错误的性质, 称为状态字:
goodbit = 0x00 表示状态正常,没有位设置。 fofbit = 0x01 表示到达文件末尾。 failbit = 0x02 表示I/O操作失败。流没有受到破坏,可以恢复。 badbit = 0x04 表示试图进行非法操作。设备硬件故障,不可恢复。 hardbit = 0x80 表示致命错误 使用clear( )函数可以清除除hardbit以外的其他错所设置的位。 返回本节

48 8.5.2 I/0流的状态函数 1.检查一个流对象当前状态的成员函数
有几个函数可用来检查一个流对象的当前状态,它们都是ios类的成 员函数: int rdstate() //返回当前的流状态字 int eof() //如果提取操作已到达文件尾,则返回非零值 int fail() //若failbit位置位,返回非零值 int bad() //若badbit位置位,返回非零值 int good() //若状态字没有置位,则返回非零值 可以使用这些函数检查当前流的状态。

49 利用函数来检测流是否出错 例如: fstream istrm("f1.dat"); if(istrm.good( ))
…               //文件打开成功,进行某些操作 例如: ofstream ostrm("f2.dat"); if(!ostrm.good( )) … //文件没有被打开,退出该程序 例如: if(!cin.eof( )) … //文件没有结束,可进行读操作 成员函数:int ios::operator !( ) 可判断流状态是否正常 ifstream istrm("f1.dat"); if(!istrm) cout << "f1.dat can't open.\n";

50 8.5.2 I/0流的状态函数 2.检查一个流对象当前状态的运算符函数
如果不关心具体是哪一位置位(具体的错误性质),则可以使用ios类 中重载的两个运算符函数: int ios::operator!(); 在设置了failbit、badbit或hardbit位的情况下返回非零,而成员函数 : ios::operator void*(); 在上述这些位没有设置的情况下(正常状态)返回非零。这两个函数提 供了从两个方面测试流状态是否为正常情况的手段。

51 8.5.2 I/0流的状态函数 3.清除/设置流状态位函数 ios类的成员函数: void ios::clear(int=0);
用于清除/设置流的状态位(它不能设置/清除hardfail位)。函数clear() 更多地是用于在己知流发生错误的情况下清除流的错误状态,也 可以用于设置流的错误状态。例如:

52 8.6 文件流操作 文件流 文件的打开与关闭 文件的读写

53 文件流 在C++中,文件被看作是元素的序列,即文件是由一个个 的元素数据顺序组成的。不考虑记录的界限,因此这种文 件称为流式文件。 按数据的存储形式来分类,文件可分为文本文件和二进制文件。 在文本文件中,每个字节存放一个ASCII代码表示一个字符,文本文 件的优点是可直接按字符形式输出,供人们阅读。 二进制文件则是把数据的内部存储形式原样存放到文件中,这种文 件的优点是与数据在内存中的存储形式保持一致,因此存储效率 高,无须进行存储形式的转换,但不能直接按字符形式输出。

54 8.6.1 文件流 按数据的存取方式来分类,文件可分为顺序文件和随机读 写文件。在C++中,文件既可以进行顺序访问,也可以进 行随机访问。
文件流 按数据的存取方式来分类,文件可分为顺序文件和随机读 写文件。在C++中,文件既可以进行顺序访问,也可以进 行随机访问。 在C++中,文件定义为文件流类的一个对象。 要进行文件的输入/输出,必须先创建—个文件流对象,并与指定 的文件相关联,即打开文件;然后才能进行读写操作;完成后再 关闭这个文件。 文件流是以外存文件为输入/输出对象的数据流。输出文件流是从内 存流向外存文件的数据,输入文件流是从外存文件流向内存的数 据。每一个文件流都有一个内存缓冲区与之对应。 C++有三种文件流:输入文件流、输出文件流和输入/输出文件流。

55 8.6.2 文件的打开与关闭 1. 打开文件 有两种方法: 先建立流对象,然后调用函数open连接外部文件 流类 对象名;
文件的打开与关闭 1. 打开文件 有两种方法: 先建立流对象,然后调用函数open连接外部文件 流类 对象名; 对象名.open(文件名,方式); 调用流类带参数的构造函数,建立流对象的同时连接外部文件 流类 对象名(文件名,方式); 其中,“流类”是C++流类库定义的文件流类,为ifstream、 ofstream或fstream。

56 文件的打开与关闭 如: ofstream ostrm; ostrm.open("f1.txt"); 或 fstream outfile(“f1.txt”, ios::out); \\写 ifstream istrm; istrm.open("f2.txt"); ifstream istrm(“f2.txt”); \\读

57 ios 文件访问方式常量 方式名 用途 in 以输入(读)方式打开文件 out 以输出(写)方式打开文件 app 以输出追加方式打开文件
方式名 用途 in 以输入(读)方式打开文件 out 以输出(写)方式打开文件 app 以输出追加方式打开文件 ate 文件打开时,文件指针位于文件尾 trune 如果文件存在,将其长度截断为0,并清除原有内容;如果文 件不存在,则创建新文件 binary 以二进制方式打开文件,缺省时为文本方式 nocreate 打开一个已有文件,如该文件不存在,打开失败 noreplace 如果文件存在,除非设置ios::ate或ios::app,否则打开操作失败 ios::in|ios::out 以读和写的方式打开文件 ios::out|ios::binary 以二进制写方式打开文件 ios::in|ios::binary 以二进制读方式打开文件

58 说明: 缺省文件的读写位置指针位于文件头 用 ios::app 方式打开文件时文件读写位置指针位于文件尾
在以ios::out方式打开文件,而未指定ios::in,ios::ate,ios::app 方式 时,则隐含为ios::trunc方式 通过"位或"操作结合起来,表示具有几种方式的操作。例如: ios::in | ios::out | ios::binary // 二进制的读写 未指定binary方式时,文件都以文本方式打开。若指定了 binary 方式,则文件以二进制方式打开

59 8.6.2 文件的打开与关闭 2. 关闭文件 当结束一个文件的操作后,要及时将该文件关闭 使用close()成员函数进行关闭:
文件的打开与关闭 2. 关闭文件 当结束一个文件的操作后,要及时将该文件关闭 使用close()成员函数进行关闭: <流对象名>. close() 其中,<流对象名>是待关闭的文件流的对象名。 例如,关闭文件标识符为 outfile 的文件,使用下面格式: outfile.close( );

60 例: 文件流被打开、关闭 #include <fstream> void main( ) { ofstream ostrm;
    ostrm.open("f1.dat");     ostrm << 12 << endl;    ostrm << <<endl;     ostrm.close( );     ifstream istrm("f1.dat");     int n;    double d;     istrm >> n >> d;    cout << n << "," << d << endl;     istrm.close( ); } Ans: 12,310.85

61 8.6.3 文件的读写 1.文本文件的读写 文本文件用默认方式打开。
文件的读写 1.文本文件的读写 文本文件用默认方式打开。 例8.7:从输入的串中分离数字串,先将其存入磁盘文件,然后将其 读出并在屏幕上显示出来。 #include <iostream> #include <fstream> using namespace std;

62 int main() { char str[10]; int i=0; cout<<"输入一个字符串(最多9个字符)“; cin
int main() { char str[10]; int i=0; cout<<"输入一个字符串(最多9个字符)“; cin.get(str,10,'!');//输入一个字符串 ofstream outfile(“f1.txt”); //以输出方式打开文件f1.txt if (!outfile) { cout<<“File cannot be opened.”<<endl; return 0; } char c=str[i]; while (i<cin.gcount()) { if (isdigit(c)) outfile<<c; //将数字串存入文件outfile if(isdigit(c) && !isdigit(str[i+1])) outfile<<endl; i=i+1; c=str[i]; }

63 outfile<<'\0'; outfile. close(); ifstream infile(“f1
outfile<<'\0'; outfile.close(); ifstream infile(“f1.txt”); //以输入方式打开文件f1.txt if (!infile) { cout<<“File cannot be opened.”<<endl; return 0; } cout<<"存入f1.txt文件中的数字串为:"<<endl; while(!infile.eof()) //从文件中读出数据,并输出到屏幕上。 { infile.getline(str,sizeof(str));//从文件中读出一行数据 cout<<str<<endl; } infile.close(); return 0;

64 例 单字符读写函数 get( )和put( ) #include <iostream> using namespace std;
#include <fstream> #include <stdlib.h> #include <string> void main( ) { fstream outfile, infile; outfile.open("f3.dat", ios::out); if(!outfile) { cout << "f3.dat can't open.\n"; abort( ); } char str[ ] = "this is a C++ program."; for(int i = 0; i<= strlen(str); i++) outfile.put(str[i]); outfile.close( );

65 例 单字符读写函数 get( )和put( ) infile.open("f3.dat", ios::in);
if(!infile) { cout << "f3.dat can't open.\n"; abort( ); } char ch; while(infile.get(ch)) cout << ch; cout << endl; infile.close( ); } Ans: this is a C++ program.

66 例: 文件拷贝 #include <iostream> using namespace std;
例: 文件拷贝 #include <iostream> using namespace std; #include <fstream> #include <stdlib.h> void main( ) { fstream infile, outfile; infile.open("f2.dat", ios::in); if(!infile) { cout << "f2.dat can‘?t open.\n"; abort( ); } outfile.open("f4.dat", ios::out); if(!outfile) { cout << "f4.dat can't open.\n"; abort( ); } char ch; while(infile.get(ch)) outfile.put(ch); infile.close( ); outfile.close( ); }

67 8.6.3 文件的读写 2.二进制文件的读写 打开二进制文件时,在 open( )函数中要加上 ios::binary
文件的读写 2.二进制文件的读写 打开二进制文件时,在 open( )函数中要加上 ios::binary 写入信息时,使用write( )函数 读信息,使用read( )函数 例8.8:用二进制文件处理学生信息 #include<iostream> #include<fstream> //文件流头文件 #include<string> using namespace std;

68 class student { private: long num; string name; float score; public: void setnum() //输入学号num { cout<<“请输入学生的学号:“; cin>>num; } void setname() //输入姓名name { cout<<"请输入学生的姓名:“; cin>>name;} void setscore() //输入学号成绩 { cout<<“请输入学生的成绩:“; cin>>score; }

69 long getnum() { return num; } // 得到学号 string getname() { return name; } //得到姓名 float getscore() { return score; } //得到成绩 }; int main() { ofstream outfile("student.dat",ios::binary); if(!outfile) { cout<<"File cannot be opened."<<endl; return 0; } student stud[100]; char ch; int i=0;

70 while(1) { cout<<"\n 你想输入更多记录吗(y/n)
while(1) { cout<<"\n 你想输入更多记录吗(y/n)? “; cin>>ch; if(ch==‘n’||ch==‘N‘) break; i=i+1; stud[i].setnum(); //输入学号 stud[i].setname(); //输入姓名 stud[i].setscore(); //输入成绩 outfile.write((char*)&stud[i],sizeof(student)); } outfile.close(); //关闭文件 cout<<"********输入结束********"<<endl;

71 cout<<"\n 你想看文件内容吗(y/n)
cout<<"\n 你想看文件内容吗(y/n)? “; cin>>ch; if(ch=='Y'||ch=='y') { ifstream infile("student.dat",ios::binary); if(!infile) { cout<<"File cannot be opened."<<endl; return 0; } cout<<"学号"<<"\t姓名"<<"\t成绩"<<endl; infile.read((char*)&stud[i],sizeof(student)); i=1; while(infile) { cout<<stud[i].getnum()<<"\t“<<stud[i].getname()<<"\t“; cout<<stud[i].getscore()<<endl; i=i+1; infile.read((char*)&stud[i],sizeof(student)); } infile.close(); //关闭文件 } return 0;

72 8.6.3 文件的读写 3.文件的随机读写 文件打开以后,系统自动生成两个隐含的流指针:读指针和写指针。
文件的读写 3.文件的随机读写 文件打开以后,系统自动生成两个隐含的流指针:读指针和写指针。 在输入文件流类中,有关读指针的函数如下: (1) 移动读指针函数 istream& istream::seekg(streampos pos); 该函数的功能是将输入文件的指针移动到pos指定的位置中。 istream& istream::seekg(streamoff offset,seek_dir origin); 其中,origin的类型seek_dir是一个枚举类型,可有以下三种取值: ios::beg 表示指针的起始位置为文件头 ios::cur 表示指针的起始位置为当前位置 ios::end 表示指针的起始位置为文件尾 该函数的功能是从origin指定的开始位置起,将文件指针移动offset 个字节数。

73 例,假设input是一个istream类型的流:
input.seekg(-100, ios::cur); 以当前位置为基准向前(流的开始位置方向)移动100各字节处 input.seekg(100, ios::beg); 从流开始的位置后移100个字节处 input.seekg(-100, ios::end); 相对于流结尾处前移100个字节处

74 文件的读写 (2)返回读指针当前指向的位置值 streampos istream::tellg( ); 该函数的功能是确定文件指针的当前位置。 相应地,ostream类提供有关写指针的函数如下: (1) 移动写指针函数 ostream& ostream::seekp(streampos pos); ostream& ostream::seekp(streamoff offset,seek_dir origin); (2)返回写指针当前指向的位置值 streampos ostream::tellp( ); 函数参数的意义与读指针函数一样。

75 例 读、写指针操作 #include <iostream.h> #include <fstream.h>
例 读、写指针操作 #include <iostream.h> #include <fstream.h> #include <stdlib.h> void main( ) {  fstream file("f6.dat", ios::in | ios::out | ios::binary);     if(!file) { cout << "f6.dat can't open.\n“;        abort( ); } for(int i=0; i<15; i++) // 每个 int,占4 个 byte          file.write((char *)&i, sizeof(int));     streampos pos = file.tellp( ); cout << "Current byte number: " << pos << endl;     for(i=15;i<45;i++)

76     file.seekg(pos); // 输入文件,读 file.read((char *)&i, sizeof(int)); cout << "The data stored is " << i << endl; file.seekp(0, ios :: beg); // 输出文件,写 for(i=80; i < 100; i++) file.write((char *)&i, sizeof(int)); file.seekg(pos); file.read((char *)&i, sizeof(int); cout<< "Current byte number: " << file.tellp( ) << endl; }

77 Ans: Current byte number: 60 The data stored is 15 The data stored is 95 The data stored is 21 Current byte number: 88

78 例: 数组 #include <iostream.h> #include <fstream.h>
#include <stdlib.h> void main( ) {   struct student     {   char name[20];         long number;        double totalscord;     } stu[5]={"Ma",97001,85.72, "Li",97002,92.62,              "Hu",97003,89.25,"Yan",97004,90.84,"Lu",97005,80.92};     fstream file;     student one;    

79 file. open("f7. dat", ios::out | ios::in | ios::binary); if (
file.open("f7.dat", ios::out | ios::in | ios::binary); if (!file1) { cout << “f7.dat can‘t open.\n‘; abort( ); } for(int i=0; i <5; i++) file1.write((char *)&stu[i], sizeof(student)); file1.seekp(sizeof(student)*4); file1.read((char *)&one, sizeof(stu[i])); cout << one.name << "\t" << one.number <<"\t" << one.totalscord << endl; file1.seekp(sizeof(student)&1); file1.read((char 8)&one, sizeof(stu[i])); cout << one.name << "\t" << one.number << "\t" << one.totalscord << endl; file1.close(); }

80 Ans: Lu Li

81 文件的读写 例8.9:用二进制文件随机处理学生信息 #include<iostream> #include<fstream> //文件流头文件 #include<string> using namespace std; class student { private: long num; string name; float score;

82 文件的读写 public: void setnum() { cin>>num; } //输入学号 void setname() { cin>>name; } //输入姓名 void setscore() { cin>>score; } //输入成绩 long getnum() { return num;} // 得到学号 string getname() { return name; } //得到姓名 float getscore() { return score; } //得到成绩 }; int main() { fstream file; file.open("student.dat",ios::in|ios::out|ios::binary); if(!file) { cout<<“File cannot be opened.”<<endl; return 0; } student stud[100],s;

83 文件的读写 cout<<"首先输入3个学生的信息:"<<endl; cout<<"学号\t姓名\t成绩"<<endl; for(int i=0;i<3;i++) { stud[i].setnum(); //输入学号 stud[i].setname(); //输入姓名 stud[i].setscore(); //输入成绩 file.write((char*)&stud[i],sizeof(student)); } cout<<"再在第2个学生后插入两个学生的信息:"<<endl; file.seekp(sizeof(student)*2); for(i=3;i<5;i++) { stud[i].setnum(); stud[i].setname(); stud[i].setscore();

84 文件的读写 cout<<"输出第2,4个学生的信息:"<<endl; cout<<"学号\t姓名\t成绩"<<endl; file.seekg(sizeof(student)*1);//读指针移到第2条记录 file.read((char*)&s,sizeof(student)); cout<<s.getnum()<<"\t”<<s.getname()<<"\t”<<s.getscore()<<endl; file.seekg(sizeof(student)*3); //读指针移到第4条记录 file.close(); //关闭文件 return 0; }

85 8.6.4 其它有关文件操作的函数 1. 跳过输入流中指定数量的字符的函数 该函数原型如下:
istream & istream::ignore(int n=1,int t=EOF); 功能是从流中跳过n个字符,或者直到发现终止符t为止 一般的使用 ctrl+z 键结束从键盘上键入的输入流

86 例:输入整数,发现错误,则跳过当前输入,等待下一次输入
void main( ) {   int a;     cout << "Input an integer: “;    cin >> a;     while(!cin) //判断输入流 cin 是否有错,有错时cin 为 0     {  cin.clear( ); //清楚错误标志位,等待下次输入        //最多跳过80字符或遇\n为止,等待下次输入 cin.ignore(80,'\n');         cout << "Try again!" << endl << "Input an integer: ";        cin >> a;    }     cout << "The integer entered is " << a <<endl; }

87 Ans: Input an integer:a789y Try again! 678a
The integer you entered is 678

88 2.退回一个字符到输入流的函数 函数原型如下: istream & istream :: putback(char ch)
功能是将读出的指定的字符退回到输出流中 ch 是指出要退回输入流的字符

89 例: 从输入流中分析出数字串 #include <iostream> #include <ctype.h> //内含 isdigit( ), 非 0 为真 int getnum(char *s); void main( ) {     char buf[80];     cout << "Enter stream:\n";     while(getnum(buf))     cout << "Digit string is: " << buf << endl; }

90 int getnum(char *s) // 每次处理一个数字串 { int flag(0); //标志量,没有数字串返回为 0 char ch; while(cin.get(ch) && !isdigit(ch)) ; if(!cin) return 0; do { *s++ = ch; }while(cin.get(ch) && isdigit(ch)); *s = '\0'; flag = 1; if(cin) cin.putback(ch); //判断字符为数字时,多读一个字符 return flag; }

91 Ans: 执行该程序显示如下信息: Enter stream: ab768 54xy128m96 n763 输出如下结果:
Digitstring is 768 Digitstring is 54 Digitstring is 128 Digitstring is 96 Digitstring is 763 按Ctrl+z键,退出该程序

92 3. 返回输入流中下一个字符的函数 函数原型为: int istream::peek( ); 功能是返回输入流中的下一个字符,但并不提取它
3. 返回输入流中下一个字符的函数 函数原型为: int istream::peek( ); 功能是返回输入流中的下一个字符,但并不提取它 在遇到输入流结束标志时返回EOF

93

94 8.7 字符串流(包含在strstrea中) I/O流库有两个类:ostrstream 和 istrstream:
ostrstream类是从ostream类派生出来的 用来将不同类型的信息格式化为字符串,并放到一个字符数组中 istrstream类是从istream类派生出来的 用来将文本项转换为变量所需要的内部格式 将一个字符串内的数字字符转换成二进制形式存放在某种 类型的对象中 将一个二进制数转换成字符存储在一个字符数组对象中

95 ostrstream类的构造函数 两个构造函数,它们的原型分别是: 进行插入操作时,并不在输出流中的末尾自动添加空字符
ostrstream::ostrstream( ); ostrstream::ostrstream(char *s, int n, int mode = ios::out); 缺省为out方式,还可选用ate和app方式。 进行插入操作时,并不在输出流中的末尾自动添加空字符 功能:建立存储所插入的数据的数组对象 Ostrstream 类还提供了如下的成员函数: int ostrstream::pcount( ): 返回流中当前已插入的字符的个数 char *ostrstream::str( ): 返回标识存储串的数组对象的指针值

96 例:构造函数 #include <iostream> #include <fstream>
#include <strstrea.h> const int N=80; void main( ) {   char buf[N];     ostrstream out1(buf, sizeof(buf));     int a = 50;     for(int i=0; i<6; i++, a+= 10)       out1 << "a=" << a << ";";     out1 << "\0“;    cout << "Buf: " << buf << endl;     double pi = ;

97 例:构造函数 ANS: out1.setf(ios::fixed | ios::showpoint); out1.seekp(0);
    out1 << "The value of pi= " << pi <<'\0';     cout << buf << endl;     char *pstr = out1.str( ); // str( ) 返回流 out1 的首址     cout << pstr << endl; } ANS: Buf:a=50;a=60;a=70;a=80;a=90;a=100; The value of pi is

98 istrstream类的构造函数 两个构造函数,它们的原型分别是: 功能: istrstream类对象可以是有名也可以是无名的。例如:
istrstream::istrstream(char*s); istrstream::istrstream(char*s,int n); 功能: 使用所指定的串的全部内容(串中前n个字符 )来构造流对象 istrstream类对象可以是有名也可以是无名的。例如: char s[ ]="1234"; istrstream(s,3); //对象是无名的 istrstream ss (s,3); //对象是有名的

99 例 构造函数 #include <iostream> #include <strstrea.h>
例 构造函数 #include <iostream> #include <strstrea.h> void main( ) {   char buf[ ] = " ";     int a;     double b;     istrstream ss(buf);     ss >> a >> b; // a = b = 45.67     cout << a + b << endl; } Ans: 168.67

100 例 #include <iostream> #include <strstrea.h> void main( )
{  char buf[ ] = "12345";     int i, j;     istrstream s1(buf);     s1 >> i; // i = 12345     istrstream s2(buf, 3);     s2 >> j; // j = 123     cout << i + j << endl; } Ans: 12468


Download ppt "第8章 C++输入输出类层次 ffh."

Similar presentations


Ads by Google