第13章C++流和文件流_第1页
第13章C++流和文件流_第2页
第13章C++流和文件流_第3页
第13章C++流和文件流_第4页
第13章C++流和文件流_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第13章C++流和文件流C++语言中没有专门的输入/输出(I/O)语句,C++中的I/O操作是通过一组标准I/O函数和I/O流来实现的。C++的标准I/O函数是从C语言继承而来的,同时对C语言的标准I/O函数进行了扩充。C++的I/O流不仅拥有标准I/O函数的功能,而且比I/O函数更方便、更可靠。13.1什么是流C++中把数据之间的传输操作称作流。在C++中,流既可以表示数据从内存传送到某个载体或设备中,即输出流;也可以表示数据从某个载体或设备传送到内存缓冲区变量中,即输入流。在进行I/O操作时,操作步骤如下:(1)打开操作,使流和文件发生联系,建立联系后的文件才允许数据流入或流出;(2)输入或输出操作;(3)结束后,使用关闭操作使文件与流断开联系。C++中所有流都是相同的,但操作的文件可以不同。使用流以后,程序用流统一对各种计算机设备和文件进行操作,使程序与设备、程序与文件无关,从而提高了程序设计的通用性和灵活性。也就是说,无论与流相联系的实际物理设备差别有多大,流都采用相同的方式运行。这种机制使得流可以跨越物理设备平台,实现流的透明运作,而与实际的物理设备无关。例如,往显示器上输出字符和向磁盘文件或打印机输出字符,尽管接收输出的物理设备不同,但具体操作过程是相同的。13.1.1预定义流在程序开始运行时,C++会自动打开4个流,这些流是C++流类库的预定义流,如下表所列。流含义所属类库默认设备cin标准输入iostream.h键盘cout标准输出iostream.h显示器cerr没有被缓冲的标准错误输出iostream.h显示器clog被缓冲了的标准错误输出iostream.h显示器C++的流通过重载运算符“<<”和“>>”执行输出和输入操作。输出操作是向流中插入一个字符序列,因此,在流操作中,将运算符“<<”称为插入运算符。输入操作是从流中提取一个字符序列,因此,将运算符“>>”称为提取运算符。1.coutcout是与标准输出设备连接的预定义输出流,称为汇。C++的插入运算符“<<”向输出流发送字符。实际上,位于插入运算符右侧的字符串被存储在“<<”左侧的流中。例如:cout<<name<<""<<number<<'\n';cout是数据的目的地,插入运算符“<<”把对象或文字数据(字符串、数字或任何对象)传送到cout。cout一般连接到标准输出设备即显示器(默认设备)。2.cincin是与标准输入设备连接的预定义输入流,称为源。它从输入流中取出数据,数据从输入提取运算符“>>”处流进程序。为了保留输入数据,输入语句要求有目的地址,即指定数据类型的存储单元,例如:inti;cin>>i;这段代码所进行的操作是:提取运算符“>>”从cin参数中提取一个整型输入数据,并存入一个对象(变量),在此例中即为整型数i。cin一般连接到标准输入设备即键盘(默认设备)。3.cerrcerr类似标准错误文件。cerr与cout的差别在于:(1)cerr是不能重定向的;(2)cerr不能被缓冲,它的输出总是直接传送到标准输出设备上。错误信息是写到cerr的项。即使在各种其他输出语句中,如果使用下列语句,则错误信息“Error”总能保证在显示器上显示出来:cerr<<"Error"<<"\n";4.clogclog是不能重定向的,但是可以被缓冲。在某些系统中,由于缓冲,使用clog代替cerr可以改进显示速度:clog<<"Error"<<"\n";13.1.2C++的流类库C++提供了一个流类库,流类库由若干完成I/O操作的基础类以及若干支持特定种类的源和目标的I/O操作类组成。流类库的基础类利用继承关系组织起来,其类层次如下图所示,这些类的说明如表13.2所列。所有使用流类库的程序必须用“#include”编译指令将iostream.h包含进来。I/O流类库的类层次输入流类istream通用输入流类和其他输入流的基类iostream.hifstream输入文件流类fstream.histream_withassigncin的输入流类iostream.histrstream输入字符串流类strstrea.h输出流类ostream通用输出流类和其他输出流的基类iostream.hofstream输出文件流类fstream.hostream_withassigncout、cerr和clog的输出流类iostream.hostrstream输出字符串流类strstrea.hI/O流类iostream通用I/O流类和其他I/O流的基类iostream.hfstreamI/O文件流类fstream.hstrstreamI/O字符串流类strstrea.h13.2格式化I/O在以前的程序中,所有I/O采用的格式都是由C++流类库提供的默认方式。在实际应用中,常常需要准确控制数据(特别是整数、浮点数与字符串)的I/O格式。流类库可用两种方法控制数据的格式:使用ios类的成员函数和使用I/O操纵符。13.2.1使用ios成员函数每一个C++流都有自己当前的数据格式控制状态,这些状态用一个长整数表示,即ios类的数据成员x_flags,称为格式化标志字。这些格式化标志字在ios类中定义为公有的枚举量。在iostream.h头文件中定义了以下枚举类型:enum{skipws=0x0001,//跳过输入中的空白(空格、制表符、回车、换行等)left=0x0002, //输出左对齐right=0x0004, //输出右对齐internal=0x0008, //在符号或基位与数值之间补齐空格dec=0x0010, //按十进制I/Ooct=0x0020, //按八进制I/Ohex=0x0040, //按十六进制I/Oshowbase=0x0080,//输出数制的基showpoint=0x0100,//强制浮点数输出小数点uppercase=0x0200,//十六进制采用大写输出showpos=0x0400,//在正数前加上“+”scientific=0x0800, //浮点数使用科学记数法fixed=0x1000,//浮点数使用普通记数法unitbuf=0x2000, //每次插入后刷新所有流stdio=0x4000 //每次插入后刷新标准输出和标准错误输出流};(1)setf()成员函数setf()用于设置状态标志。例如,设置输出流cout的showbase标志使用如下语句:

cout.setf(ios::showbase);设置输入流cin的skipws标志使用如下语句:

cin.setf(ios::skipws);

注意:格式标志前的限定“ios::”不可缺少,因为这些标志是在ios类中定义的。在setf()中还可用位或操作“|”将多个标志连在一起。例如:

cout.setf(ios::scientific|ios::showpoint);同时设置scientific和showpoint两个标志。(2)unsetf()成员函数unsetf()用来取消格式标志,unsetf()的用法与setf()相似。(3)flags()成员函数flags()用于获取当前格式标志的状态,即返回保护成员x_flags的当前值。(4)precision()该函数的说明如下:intprecision([intnum]);用于设置或返回(不带参数时)浮点数的输出精度,也就是通过这个公共成员函数设置ios类的保护数据成员x_precision的值,该成员的默认值为6。precision()函数的设置值一直有效,直到下一个precision()函数改变该值为止。(5)width()该函数的说明如下:intwidth([intlen]);用于设置或返回(不带参数时)输出数据的字段宽度,也就是通过这个公共成员函数设置ios类的保护数据成员x_width的值。width()函数的设置值只对下一个输出有效。(6)fill()该函数的说明如下:charfill([charch]);用于设置或返回(不带参数时)输出的填充字符,也就是通过这个公共成员函数设置ios类的保护数据成员x_fill的值,该成员的默认值为空格。fill()函数的设置值一直有效,直到下一个fill()函数改变该值为止。【例】分析以下程序的执行结果。#include<iostream.h>voidmain(){intn=123;doubled=1234.5678;cout.precision(10);cout.width(10);cout.fill('*');cout<<n<<endl;cout<<d<<endl;cout.precision(6);cout.width(6);cout<<n<<endl;cout<<d<<endl;}*******1231234.5678***1231234.57

右对齐13.2.2使用I/O操纵符除ios类成员函数之外,C++的流类库还提供了另一种更方便的I/O格式化方法,这种方法使用一种称为操纵符的特殊函数,操纵符的特点是可以直接包含在I/O表达式中。所有不带形参的操纵符都定义在头文件iostream.h中,而带形参的操纵符则定义在头文件iomanip.h中,因而使用相应的操纵符就必须包含相应的头文件。表13.3列出了这些I/O操纵符。已在第3章已介绍,这是不再讨论。13.3重载I/O运算符C++的I/O系统的另一个优点是可以重载I/O运算符。通过重载I/O运算符,可以建立适合于类需要的输入和输出界面。I/O运算符重载的实质就是把用于变量输入输出的运算符转化为对于类对象的输入输出操作。13.3.1重载输出运算符“<<”在C++中,输出操作称为插入,“<<”称为插入运算符。当重载输出运算符“<<”用于输出时,相当于创建一个插入符函数。插入符函数的格式如下:

friendostream&operator<<(ostream&stream,类名&类引用名){函数体;returnstream;}该插入符函数是以友元方式说明的。其中的第一个参数是ostream类对象的一个引用,即stream必须是一个输出流。“类引用名”接收待输出的对象。该函数返回ostream的一个引用stream。“函数体”中给出实现该插入符重载目的的代码。【例】分析以下程序的执行结果。#include<iostream.h>classSample{intx,y;public:Sample(intm,intn){x=m;y=n;}friendostream&operator<<(ostream&stream,Sample&s){cout<<"x="<<s.x<<",y="<<s.y<<endl;returnstream;}};voidmain(){SampleA(1,2),B(3,4);cout<<A<<B;}x=1,y=2x=3,y=413.3.2重载输入运算符“>>”在C++中,“>>”运算符称为提取运算符,对它进行重载的函数称为提取符函数。这个运算符函数接收流的输入信息。其格式如下:

friendistream&operator>>(istream&stream,类名&类引用名){函数体;returnstream;}该提取符函数是以友元方式说明的。其中的第一个参数是istream类对象的一个引用,即stream必须是一个输入流。“类引用名”接收输入对象的引用。该函数返回istream的一个引用stream。“函数体”中给出实现该提取符重载目的的代码。【例】分析以下程序的执行结果。#include<iostream.h>classSample{intx,y;public:Sample(){}friendistream&operator>>(istream&stream,Sample&s){cout<<"输入x和y的值"<<endl;cout<<"x:";stream>>s.x;cout<<"y:";stream>>s.y;returnstream;}friendostream&operator<<(ostream&stream,Sample&s){cout<<"输出x和y的值"<<endl;cout<<"x="<<s.x<<",y="<<s.y<<endl;returnstream;}};voidmain(){SampleA;cin>>A;cout<<A;}输入x和y的值x:5<Enter>y:8<Enter>输出x和y的值x=5,y=813.4检测流操作的错误在I/O流的操作过程中可能出现各种错误,每一个流都有一个状态标志字,以指示是否发生了错误以及出现了哪种类型的错误,这种处理技术与格式控制标志字是相同的。ios类定义了以下枚举类型:enumio_state{goodbit=0x00,//不设置任何位,一切正常eofbit=0x01,//输入流已经结束,无字符可读入failbit=0x02,//上次读/写操作失败,但流仍可使用badbit=0x04,//试图作无效的读/写操作,流不再可用hardfail=0x80//不可恢复的严重错误};对应于这个标志字各状态位,ios类还提供了以下成员函数来检测或设置流的状态:intrdstate(); //返回流的当前状态标志字inteof(); //返回非0值表示到达文件尾intfail(); //返回非0值表示操作失败intbad(); //返回非0值表示出现错误intgood(); //返回非0值表示流操作正常intclear(intflag=0); //将流的状态设置为flag为提高程序的可靠性,我们应在程序中检测I/O流的操作是否正常。当检测到流操作出现错误时,可以通过异常处理来解决问题。13.5文件流文件是存储在磁盘、磁带等外部设备上的数据集合,每一个文件都必须有一个惟一名字。使用文件前必须首先打开,使用完毕后必须关闭文件。对文件的操作是由文件流类完成的。文件流类在流与文件之间建立连接,使用这些文件流类必须用#include编译指令将头文件fstream.h包含进来。13.5.1文件的打开与关闭流可以分为3类:输入流、输出流以及输入/输出流,相应地必须将流说明为ifstream、ofstream以及fstream类的对象。例如:ifstreamifile; //说明一个输入流ofstreamofile; //说明一个输出流fstreamiofile; //说明—个输入/输出流说明了流对象之后,可使用函数open()打开文件。文件的打开即是在流与文件之间建立一个连接。open()的函数原型为:voidopen(constchar*filename,intmode,intprot=filebuf::openprot);其中,filename是文件名字,它可包含路径说明。mode说明文件打开的模式,它对文件的操作影响重大,mode的取值必须是以下值之一:•

ios::in打开文件进行读操作•

ios::out打开文件进行写操作•

ios::ate打开时文件指针定位到文件尾•

ios::app添加模式,所有增加都在文件尾部进行•

ios::trunc如果文件已存在则清空原文件•

ios::nocreate如果文件不存在则打开失败•

ios::noreplace如果文件存在则打开失败•

ios::binary二进制文件(非文本文件)对于ifstream流,mode的默认值为ios::in;对于ofstream流,mode的默认值为ios::out。prot决定文件的访问方式,取值如下:•

0普通文件•

1只读文件•

2隐含文件•

4系统文件一般情况下,该访问方式使用默认值。与其他状态标志一样,mode的符号常量可以用位或运算“|”组合在一起,如ios::in|ios::binary表示以只读方式打开二进制文件。例如:ifstreamifile;ifile.open("c:\\vc\\abc.txt",ios::ate);表示以文本文件形式打开C:\vc目录下的abc.txt文件,文件指针定位到文件尾,准备进行读文件操作。而操作:ofstreamofile;ofile.open("c:\\vc\\abc.txt",ios::binary);表示以二进制文件形式打开C:\vc目录下的abc.txt文件,准备进行写文件操作。其中,文件名中“\\”的第一个“\”为转义字符。除了open()成员函数外,ifstream、ofstream和fstream三类流的构造函数也可以打开文件,其参数同open()函数。例如:ifstreamifile("c:\\vc\\abc.txt");说明一个输入流对象的同时,将这个流与文件“c:\vc\abc.txt”连接起来,使流ifile可以用文本形式对该文件进行读操作。13.5.2文件的读写通过打开文件就建立I/O流与文本文件的连接,之后就可以进行文件的读写操作了。1.文件读写方法在C++中提供了几种文件读写方法。(1)使用流运算符直接读写。文件的读/写操作可以直接使用流的插入运算符“<<”和提取运算符“>>”,这些运算符将完成文件的字符转换工作。

(2)使用流成员函数。常用的输出流成员函数如下:

•put函数该函数把一个字符写到输出流中。下面两个语句默认是相同的,但第二个受该流的格式化参数的影响:

cout.put('A');//精确地输出一个字符cout<<'A';//输出一个字符,但此前设置的宽度和填充方式在此起作用•write函数该函数把内存中的一块内容写到一个输出文件流中,长度参数指出写的字节数。write函数当遇到空字符时并不停止,因此能够写入完整的类结构,该函数带两个参数:一个char指针(指向内存数据的起始地址)和一个所写的字节数。

注意,在该结构对象的地址之前需要char做强制类型转换。常用的输入流成员函数如下:

get函数该函数的功能与提取运算符(>>)很相似,主要的不同点是get函数在读取数据时包括空白字符,而提取运算符在默认情况下拒绝接受空白字符。

•getline函数该函数的功能是允许从输入流中读取多个字符,并且允许指定输入终止字符(默认值是换行字符),在读取完成后,从读取的内容中删除该终止字符。•read函数该函数从一个文件读字节到一个指定的存储器区域,由长度参数确定要读的字节数。虽然给出长度参数,但当遇到文件结束或者在文本模式文件中遇到文件结束标记字符时读就结束。2.文本文件的读写文本文件只适用于那些解释为ASCII码的文件。处理文本文件时将自动作一些字符转换,如输出换行字符0x0A时将转换为回车0x0D与换行0x0A两个字符存入文本文件,读入时也会将回车与换行两个字符合并为一个换行字符,这样内存中的字符与写入文件中的字符之间就不再是一一对应关系。文本文件的结束以ASCII码的控制字符0x1A表示。【例】分析以下程序的执行结果。#include<iostream.h>#include<fstream.h>intmain(){ofstreamofile("test");//打开test文件用于写,即输出if(!ofile){cout<<"test文件不能打开"<<endl;return0;}ofile<<"ThisbookisC++"<<""<<12345<<endl;ofile.close();ifstreamifile("test");//打开test文件用于读,即输入if(!ifile){cout<<"test文件不能打开"<<endl;return0;}charstr[80];ifile>>str;ifile.close();cout<<str<<endl;return1;}本程序先在当前目录下建立一个test文本文件,并写入“ThisbookisC++12345”数据,然后打开该文件,将其中的数据输入到变量str中,由于读时遇到空格时终止,所以str为“This”。程序的执行结果如下:This【例】编写一个程序,将文本文件abc.txt复制到文本文件xyz.txt。解:使用输入流成员函数get()从文本文件abc.txt中读取一个字符ch,然后使用输出流成员函数put()将字符ch写入文本文件xyz.txt中,继续这一过程直到get()读完为止。实现本例功能的程序如下:#include<iostream.h>#include<fstream.h>intmain(){ifstreamifile("abc.txt");charch;if(!ifile){cout<<"abc.txt文件不能打开"<<endl;return0;}ofstreamofile("xyz.txt");if(!ofile){cout<<"xyz.txt文件不能打开"<<endl;return0;}while(ifile.get(ch))ofile.put(ch);ifile.close();ofile.close();return1;}3.二进制文件的读写二进制文件不同于文本文件,它可用于任何类型的文件(包括文本文件),读写二进制文件的字符不作任何转换,读写的字符与文件之间是完全一致的。一般地,对二进制文件的读写可采用两种方法:一种是使用get()和put();另一种是使用read()和write()。【例】以下程序建立一个输出文件流并将一个Date结构体变量的二进制值写入到该文件中。#include<fstream.h>structDate{ intmo,da,yr;};voidmain(){Datedt={2,20,2001};ofstreamofile("data.dat",ios::binary);ofile.write((char*)&dt,sizeofdt);ofile.close();}4.文件的随机读写每一个文件都有两个指针:一个是读指针,说明输入操作当前在文件中的位置;另一个是写指针,说明下次写操作的当前位置。每次执行输入或输出时,相应的读/写指针将自动向后移动。C++语言的文件流不仅可以按这种顺序方式进行读/写,而且还可以随机地移动文件的读/写指针。有一些外部设备(如磁带、行式打印机等)关联的流只能作顺序访问,但在许多情况下使用随机方式访问文件更加方便灵活。(1)输出流随机访问函数输出流随机访问函数有seekp和tellp。一个输出文件流保存一个内部指针以指出下一次写数据的位置。seekp成员函数设置这个指针,因此可以以随机方式向磁盘文件输出。tellp成员函数返回该文件位置指针值。这两个成员函数的原型如下:ostream&ostream::seekp(流中的位置);ostream&ostream::seekp(偏移量,参照位置);streamposostream::tellp();其中,streampos被定义为long型,并以字节数为单位。“参照位置”具有如下含义:•

cur=1相对于当前写指针所指定的位置。•

beg=0相对于流的开始位置。•

end=2相对于流的结尾处。(2)输入流随机访问函数。输入流随机访问函数有seekg和tellg。在输入文件流中,保留着一个指向文件中下一个将要读数据的位置的内部指针,可以用seekg函数来设置这个指针。使用seekg可以实现面向记录的数据管理系统,用固定长度的记录大小乘以记录号便得到相对于文件末尾的字节位置,然后使用get读这个记录。tellg成员函数返回当前文件读指针的位置,这个值是streampos类型,该typedef结构定义在iostream.h中。这两个成员函数的说明原型如下:istream&istream::seekg(流中的位置);istream&istream::seekg(偏移量,参照位置);streamposistream::tellg();其中,streampos被定义为long型,并以字节数为单位。“参照位置”具有如下含义:

cur=1相对于当前读指针所指定的位置。

beg=0相对于流的开始位置。

end=2相对于流的结尾处。【例】编写一个程序,在文件City.dat中输入几个城市的名称和区号,并根据用户输入的区号查找对应的城市。解

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论