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

Slides:



Advertisements
Similar presentations
第 2 章 初探 C++.
Advertisements

程序设计实习 3月份练习解答
補充: Input from a text file
第11章 输入输出流类.
第4章 数组 数组是由一定数目的同类元素顺序排列而成的结构类型数据 一个数组在内存占有一片连续的存储区域 数组名是存储空间的首地址
流类库与输入/输出 输入/输出标准流类 文件流类 串流类 输入/输出成员函数 用户自定义类型的输入/输出.
第八章 类和对象.
C++程序设计 王希 图书馆三楼办公室.
C++的檔案處理 綠園.
資料大樓 --談指標與陣列 綠園.
计算概论 第二十一讲 文件操作 北京大学信息学院.
C++程序设计 第二讲 清华大学软件学院.
刘胥影 东南大学计算机学院 面向对象程序设计1 2011~2012第3学期 刘胥影 东南大学计算机学院.
教材 《C++程序设计》.谭浩强. 清华大学出版社 王雪晶
第七章 I/O流.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
西安交通大学 计算机教学实验中心 大学C++程序设计教程 西安交通大学 计算机教学实验中心
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Object-Oriented Programming in C++ 第一章 C++的初步知识
第三章 C++中的C 面向对象程序设计(C++).
2 C++ 的基本語法和使用環境 親自撰寫和執行程式是學好程式語言的不二法門。本章藉由兩個簡單的程式,介紹C++ 程式的基本結構和開發環境,讓初學者能逐漸建立使用C++ 的信心。
第9章 C++的文件操作 “文件”,一般是指内存以外的存储介质上一批数据的集合。C++在语言层次上提供了文件操作的一系列函数用于完成文件的操作,打开、关闭文件,读取、写入文件数据等操作。 1。字符文件与二进制文件 字符文件:又称ASCII文件或文本TEXT文件,它是以一个字节存放一个ASCII码,代表一个字符。例如,32767需要使用5个字节表示,即:
檔案 將資料存入磁碟或由磁碟取出資料的方式, 稱為檔案存取處理。 C語言的檔案處理 C++語言的檔案處理.
第八章 文件 引述 输入输出流和文件概述 文件操作 流的格式化输出 程序举例 本章小节.
第3讲 C++程序控制结构 3.1 顺序结构 3.2 分支结构 3.3 循环结构 3.4 转向控制 3.5 综合案例分析.
第13章 输入输出流 王雪晶.
类类型 C++支持的内置类型和操作,如 int i=10; i=i%6; i=i+4;
C++语言程序设计 第二章 C++简单程序设计.
第九章 C++的I/O流库 9.1 流 9.2 磁盘文件 9.3 程序举例.
程序的三种基本结构 if条件分支语句 switch多路开关语句 循环语句 循环嵌套 break,continue和goto语句
第八章 文件 引述 输入输出流和文件概述 文件操作 流的格式化输出 程序举例 本章小节.
谭浩强 编著 中国高等院校计算机基础教育课程体系规划教材 C++程序设计.
C++语言程序设计 第十一章 流类库与输入/输出.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
10 多載函數 10.1 多載概論 多載一般函數 多載成員函數 10-3
第 14 章 輸出與輸入.
C++大学基础教程 第5章 数组 北京科技大学 信息基础科学系.
第十三讲 文件流与 输出输入重载.
C++ 程式設計 基礎篇 張啟中 Chang Chi-Chung.
C++大学基础教程 第3章 C++控制语句 北京科技大学 信息基础科学系.
第14章 输入输出与文件 输入输出是指程序与外部设备交换信息 C++把输入输出看成是一个数据流 输入流:外围设备流向内存的数据
第二章 基本数据类型及运算 C数据类型概述 基本数据类型 运算符和表达式 混合运算与类型转换 数据的输入输出 顺序程序设计举例.
Chapter 2 & Chapter 3.
第7章 输入/输出流 文件和I/O流概述 标准I/O流的对象及其成员函数 文件流.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第三章 控制语句 第十一组 C++语言程序设计.
第3章C++面向对象程序设计 3.1 类和对象 作业1 3.2 继承和派生类 作业2 3.3 多态和虚函数 3.4 运算符重载 作业3
物件導向程式設計 CH2.
C++的檔案處理 綠園.
第11章 從C到C++語言 11-1 C++語言的基礎 11-2 C++語言的資料型態與運算子 11-3 C++語言的輸出與輸入
C++程式設計入門 變數與運算子 作者:黃建庭.
C++大学基础教程 第10章 运算符重载 北京科技大学 2019/5/7 北京科技大学.
第十一章 IO流与文件系统 丘志杰 电子科技大学 计算机学院 软件学院.
C++程序设计基础 主讲人:谢昕 华东交通大学信息工程学院 第十~十二讲 多态性和虚函数 2005年春季学期.
C/C++基礎程式設計班 C++: 物件的使用、參考、重載函式 講師:林業峻 CSIE, NTU 3/28, 2015.
第1章 C++面向对象程序设计要点 1.1 函数和函数参数 1.2 输入输出   1.3 类 1.4 抽象类型和模板.
第 3 章 类的基础部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
#include <iostream.h>
C++语言程序设计 C++语言程序设计 第十章 多态 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
第2章 文件操作 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.
C++语言程序设计 C++语言程序设计 第十一章 异常处理 C++语言程序设计.
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
變數與資料型態  綠園.
第六章 复合数据类型 指针的声明与使用 数组的声明与使用 指针与数组的相互引用 字符串及相关库函数 new与delete
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

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

目录 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 字符串流

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

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

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

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

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

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

支持文件的流类

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

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

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

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

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) :该函数用来清除参数所指定的那些标志位, 并返回更新前的标志字。

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=+1.234000e+001

8.2.1 使用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; }

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

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

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

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

运行结果: 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****, 4358.2

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

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

8.2.2 使用控制符进行格式控制 例8.4 使用控制符进行格式控制,完成例8.3同样的功能。 #include <iostream> #include <iomanip> using namespace std; int main() { double values[] = {1.23,35.36,653.7,4358.24}; 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; }

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

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; };

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; }

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; }

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

8.4.1 输入流的常用成员函数 1.read()函数 istream& read(char*pch,int nCount); 8.4.1 输入流的常用成员函数 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; }

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

8.4.1 输入流的常用成员函数 2.get()函数 该函数有3种主要形式:  istream& int get() 8.4.1 输入流的常用成员函数 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时终止。

例: 从键盘输入 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!

8.4.1 输入流的常用成员函数 3.getline() 4.gcount()函数 8.4.1 输入流的常用成员函数 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";

    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; }

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

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

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

例 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

8.4.2 输出流的常用成员函数 1.write()函数 ostream& write(const *str, int n); 8.4.2 输出流的常用成员函数 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“; }

例: 函数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

8.4.2 输出流的常用成员函数 2. put()函数 ostream& put(char ch ); 输出一个字符。 8.4.2 输出流的常用成员函数 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

8.4.2 输出流的常用成员函数 例8.6:从输入的串中分离数字串,示例常用成员函数I/O 8.4.2 输出流的常用成员函数 例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;

8.4.2 输出流的常用成员函数 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; }

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

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

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

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

利用函数来检测流是否出错 例如: 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";

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

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

8.6 文件流操作 8.6.1 文件流 8.6.2 文件的打开与关闭 8.6.3 文件的读写

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

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

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

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

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 以二进制读方式打开文件

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

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

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

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

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]; }

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;

例 单字符读写函数 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( );

例 单字符读写函数 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.

例: 文件拷贝 #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( ); }

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

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; }

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;

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;

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;

8.6.3 文件的读写 3.文件的随机读写 文件打开以后,系统自动生成两个隐含的流指针:读指针和写指针。 8.6.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 个字节数。

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

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

例 读、写指针操作 #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++)

    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; }

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

例: 数组 #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;    

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(); }

Ans: Lu 97005 80.92 Li 97002 92.62

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

8.6.3 文件的读写 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;

8.6.3 文件的读写 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();

8.6.3 文件的读写 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; }

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

例:输入整数,发现错误,则跳过当前输入,等待下一次输入 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; }

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

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

例: 从输入流中分析出数字串 #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; }

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; }

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

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

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

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

例:构造函数 #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 = 3.14159265;

例:构造函数 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 3.14159265

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

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

例 #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