语言-杂谈程序i0流类库_第1页
语言-杂谈程序i0流类库_第2页
语言-杂谈程序i0流类库_第3页
语言-杂谈程序i0流类库_第4页
语言-杂谈程序i0流类库_第5页
已阅读5页,还剩63页未读 继续免费阅读

下载本文档

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

文档简介

第9章

I/O流类库

9.1什么是流

9.2格式化输入输出

9.3文件I/O

9.4字符串流

9.1什么是流

C++中把数据之间的传输操作称作流。在C++中,流既可以表示数据从内存传送到某个载体或设备中,即输出流;也可以表示数据从某个载体或设备传送到内存缓冲区变量中,即输入流。在进行I/O操作时,首先打开操作,使流和文件发生联系,建立联系后的文件才允许数据流入或流出,输入或输出结束后,使用关闭操作使文件与流断开联系。

C++中所有流都是相同的,但文件可以不同。使用流以后,程序用流统一对各种计算机设备和文件进行操作,使程序与设备、程序与文件无关,从而提高了程序设计的通用性和灵活性。也就是说,无论与流相联系的实际物理设备差别有多大,流都采用相同的方式运行。

9.1.1预定义流

9.1.2C++的流类库9.1.1预定义流

在程序开始运行时,C++会自动打开4个流,这些流类库的预定义流,如下表9.1所示。流含义所属类库默认设备cin标准输入iostream.h键盘cout标准输出iostream.h显示器cerr没有被缓冲的标准错误输出iostream.h显示器clog被缓冲了的标准错误输出iostream.h显示器表9.1C++流库的预定义流

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”总能保证在显示器上显示出来:4、clog

clog是不能重定向的,但是可以被缓冲。在某些系统中,由于缓冲,使用clog代替cerr可以改进显示速度:

clog<<“Error”<<“\n”;9.1.2C++的流类库C++提供了一个流类库,流类库由若干完成I/O操作的基础类以及若干支持特定种类的源和目标的I/O操作类组成。流类库的基础类利用继承关系组织起来,其类层次如图9.1所示,这些类的说明如表9.2所列。所有使用流类库的程序必须用“#include”编译指令将iostream.h包含进来。ostrstreamostream_withassignistream_withassignistrstreamiostreamfstreamstrstreamofstreamifstreamostreamistreamios图9.1I/O流类库的类层次

表9.2I/O流类库

9.2格式化输入输出

流类库可用两种方法控制数据的格式:使用流对象的成员函数和使用I/O控制符。

1、使用流对象的成员函数

2、用控制符

manipulators(控制符)是在头文件iomanip.h中定义的对象,与成员函数调用效果一样。控制符的优点是程序可以直接将它们插入流中,不必单独调用。例9.1下面的程序改变输出精度#include<iostream.h>voidfn(floatinterest,floatamount){cout<<“RMBamount=”;cout.precision(2);//置有效位数为2位

cout<<amount;cout<<“\ntheinterest=”;cout.precision(4);//置有效位数为4位

cout<<interest<<endl;}voidmain(){floatf1=29.41560067;floatf2=12.567188;fn(f1,f2);}运行结果为:RMBamount=13theinterest=29.42precision()为cout对象的成员函数,在要求输出一定精度的数据之前,先调用这个精度设置成员函数。例9.2用控制符设置小数精度,重写例9.1(考虑两程序的执行结果)#include<iostream.h>#include<iomanip.h>voidfn(floatinterest,floatamount){cout<<“RMBamount=”<<setprecision(2)<<amount;cout<<“\ntheinterest=”<<setprecision(4)<<interest<<endl;}voidmain(){floatf1=29.41560067;floatf2=12.567188;fn(f1,f2);}常用控制符和流格式控制成员函数如表9.3所示。表9.3常用控制符与流控制成员函数

控制符和流成员函数相对应,它们用法不同,但作用相同。其中setw(n)或width(n)很特别,他们在下一个域输出后,又回到原先的默认值。例9.3输出下面的两个数#include<iostream.h>#include<iomanip.h>voidmain(){cout.width(8);cout<<10<<20<<endl;}运行结果为:______1020运行结果中的下横线表示空格。整数20并没有按宽度8输出。例9.4给出下列程序的执行结果

#include<iostream.h>#include<iomanip.h>voidmain(){for(intn=1;n<8;n++)cout<<setfill(‘’)<<setw(n)<<“”<<setfill(‘a’)<<setw(15-2*n)<<“a”<<endl;}运行结果为:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa9.3文件I/O

在C++中,把文件看成是由一系列字节所构成的字节串,称为流式文件,对文件中数据的操作(输入/输出)通常是逐个字节顺序进行。在对文件数据进行读写前,首先要打开文件。打开文件的目的是:在程序内部的一个表示文件的变量与外部的一个具体文件之间建立联系。每个打开的文件都有一个内部的位置指针,它指出文件的当前读写位置。

9.3.1基于I/O函数库的文件I/O

9.3.2基于I/O类库的文件I/O9.3.1基于I/O函数库的文件I/OC++从C语言标准库保留下来的输入/输出函数库中包含了对文件进行输入/输出操作的函数。程序中应有下面的文件包含命令:

#include<cstdio>//或#include<stdio.h>1、文件的输出操作

(1)

打开文件。打开外部文件输出数据要用下面的函数fopen来实现:FILE*fopen(constchar*filename,constchar*mode);//打开方式

其中,filename是要打开的外部文件名;mode表示打开方式,它可以是:“w”:打开一个外部文件用于写操作,如果外部文件已存在,则首先把它的内容清除;否则,先创建该外部文件。“a”:打开一个外部文件用于添加(从文件末尾)操作。如果外部文件不存在,则先创建该外部文件。(2)输出操作。文件打开成功后就可以往文件中写入数据了。往文件中写入数据的函数主要有以下几个://输出一个字符,输出成功时返回输出的字符。intfputc(intc,FILE*stream);//输出一个字符串,输出成功时返回一个非负整数。intfputs(constchar*string,FILE*stream);//输出基本类型数据,返回输出的字符数。intfprintf(FILE*stream,constchar*format[,argument]…);//按字节输出数据。参数size为字节块的尺寸;count为字节块的个数。返回实际输出的字节块的个数。

size_fwrite(constvoid*buffer,size_tsize,size_tcount,FILE*stream);

(3)关闭文件。文件操作结束后需要执行关闭操作:

intfclose(FILE*stream);//关闭文件上面的函数返回0表示成功。例9.5从键盘输入一批学生的成绩信息,并把它们以文本格式存入外部文件scores.txt。#include<cstdio>usingnamespacestd;intmain(){FILE*fp=fopen(“d:\\scores.txt”,“w”);//以文本方式打开文件用于输出

if(fp==NULL)//判断文件打开是否成功

{printf(“打开文件失败!\n”);return–1;}charid[11],name[9];intnum_of_courses,score;printf(“请输入学号、姓名、选课数及各门课成绩(以学号为‘E’结束):\n”);scanf(“%10s”,id);//读入第一个学生的学号while(id[0]!=’E’)//判断输入是否结束

{scanf(“%8s”,name);//读入姓名

scanf(“%d”,&num_of_courses);//读入选课数

fprintf(fp,“%s%s%d”,id,name,num_of_courses);//把学号、姓名和选课数输出到文件

for(inti=0;i<num_of_courses;i++)//循环读入各门课成绩并输出到文件

{scanf(“%d”,&score); fprintf(fp,“%d”,score); }fputc(‘\n’,fp);//输出一个换行符到文件

scanf(fp);//读入下一个学生的学号

}fclose(fp);}上面程序的输入格式为:001张三470808590↙002李四58560759080↙……E↙例9.6从键盘读入一批学生的信息,并把它们以二进制格式存入外部文件students.dat

。#include<cstdio>usingnamespacestd;enumSex{MALE,FEMALE};structDate{intyear;intmonth;intday;};EnumMajor{MATHEMATICS,PHYSICS,CHEMISTRY,COMPUTER,GEOGRAPHY,ASTRONOMY,ENGLISH,CHINESE,PHILOSOPHY};structstudent{charid[11];charname[9];Sexsex;Datebirth_date;charbirth_place[40];Majormajor;};intmain(){FILE*fp=fopen(“d:\\students.dat”,“wb”);//以二进制方式打开文件用于输出

if(fp==NULL)//判断文件打开是否成功

{printf(“打开文件失败!\n”); return–1; }Studentst;printf(“输入学号、姓名、性别、出生日期、出生地和专业(以学号为‘E’结束)\n”);scanf(“%10s”,st.id);//读入第一个学生的学号while(st.id[0]!=’E’){……//读入姓名、性别、出生日期、出生地和专业到变量st中fwrite(&st,sizeof(st),1,fp);//以二进制格式输出变量st的值到文件

scanf(“%10s”,st.id);//读入下一个学生的学号}fclose(fp);//关闭文件}2、文件的输入操作

(1)打开文件。打开外部文件输入数据要用下面的函数fopen来实现:

FILE*fp=fopen(constchar*filename,constchar*mode);其中,filename是要打开的外部文件名;mode是打开方式,它可以是“r”,表示打开一个外部文件用于读操作,这时,外部文件必须存在,否则打开文件失败。

(2)输入操作。从文件中输入数据的函数主要有以下几个:

//输入一个字符,返回字符的编码。

intfgetc(FILE*stream);

//输入一个字符串,函数正常结束时返回string的值,否则返回NULL。

char*fgets(char*string,intn,FILE*stream);

//输入基本类型的数据,返回值表示读入并存储的数据个数。

intfscanf(FILE*stream,constchar*format[,argument]…);

//按字节输入数据。参数size为字节块的尺寸;

count为字节块的个数。返回值表示读入的字节块的个数。

size_tfread(constvoid*buffer,size_tsize,size_tcount,FILE*stream);//判断文件结束.当文件位置指针在文件末尾时,进行一次读操作之后将使得feof返回非零

(true)。

intfeof(FILE*stream);(3)关闭文件。文件操作结束时应关闭打开的文件:

fclose(FILE*stream);例9.7从例9.5输出的文件中读入数据,计算每个学生的平均成绩并输出到显示器。本章例9.5输出的文件是以文本方式组织的,因此,读入该文件数据时也要以文本方式进行。#include<cstdio>usingnamespacestd;intmain(){FILE*fp=fopen(“d:\\scores.txt”,“r”);//以文本方式打开文件用于输入

If(fp==NULL)//判断文件打开是否成功

{printf(“打开文件失败!\n”);return-1;}charid[11],name[9];intnum_of_courses,score,total;fscanf(fp,“%10s”,id);//读入第一个学生的学号while(!feof(fp))//判断文件结束标记{fscanf(fp,“%8s”,name);//读入姓名

fscanf(fp,“%d”,&num_of_courses);//读入选课数

total=0;for(inti=0;i<num_of_courses;i++)//循环读入各门课成绩并加到total上去

{fscanf(fp,“%d”,&score); total+=score;}printf(“%s,%s,%d\n”,id,name,total/num_of_courses);//输出结果fscanf(fp,“%10s”,id);//读入下一个学生的学号

} fclose(fp);//关闭文件

}例9.8从例9.6输出的文件中读入数据,统计男生的人数。本章例9.6输出的文件是以二进制方式组织的,因此,读入该文件数据时也要以二进制方式进行。#include<cstdio>usingnamespacestd;……//省略了Sex、Date、Major以及Student的定义。intmain(){FILE*fp=fopen(“d:\\students.dat”,“rb”);//以二进制方式打开文件用于输入

If(fp==NULL)//判断文件打开是否成功

{printf(“打开文件失败!\n”);return-1;}Studentst;

intcount=0;fread(&st,sizeof(st),1,fp);//读入第一个学生的信息while(!feof(fp)){if(st.sex==MALE)count++;fread(&st,sizeof(st),1,fp);//读入下一个学生的信息}printf(“男生的人数是:%d\n”,count);fclose(fp);}3、文件的输入/输出操作以“w”或“a”方式打开的文件只能对其进行输出操作;以“r”方式打开的文件只能对其进行输入操作。如果需要打开一个文件既能用于输出又能用于输入(读写方式),则应采用下面的函数打开文件:

FILE*fopen(constchar*filename,constchar*mode);其中,mode可以是:·

“r+”:打开一个外部文件用于读/写操作。文件必须存在。·

“w+”:打开一个外部文件用于读/写操作。如果文件不存在,则首先创建一个空文件,否则,首先清空已有文件中的内容。·

“a+”:打开一个外部文件用于读/添加操作。如果文件不存在,则首先创建一个空文件。以这种方式打开的文件,输出操作总是在文件尾进行。另外,在r+、w+或a+的后面还可以加上t或b,以区别文本或二进制方式打开文件。4、随机输入/输出每个打开的文件都有一个位置指针,指向当前读/写位置,每读入或写出一个字符,文件的位置指针都会自动往后移动一个位置。除了自动移动文件位置指针外,文件位置指针也可以用一个函数来显式地指定:

intfseek(FILE*stream,longoffset,intorigin);//显式地指定位置指针的位置其中,origin指出参考位置,它可以是SEEK_CUR(当前位置)、SEEK­_END(文件末尾)或SEEK_SET(文件头);offset为移动的字节数(偏移量),它可以为正值(向后移动)或负值(向前移动)。

Longftell(FILE*stream);//返回位置指针的位置。例9.9读入例9.6生成的文件(students.dat)中的第二个学生的信息,把该学生的专业修改成COMPUTER,然后把它写回文件中。(考虑程序的执行结果)

#include<cstdio>usingnamespacestd;……//省略了Sex、Date、Major以及Student的定义。intmain(){FILE*fp=fopen(“d:\\students.dat”,“r+b”);//以二进制方式打开文件用于输入/输出

If(fp==NULL)//判断文件打开是否成功

{printf(“打开文件失败!\n”);return-1;}studentst;if(fseek(fp,sizeof(st),SEEK_SET)==0)//文件位置指针指向第二个学生数据{fread(&st,sizeof(st),1,fp);//读入第二个学生数据,文件位置指针移至下一个学生数据 PUTER;//修改第二个学生数据的专业 fseek(fp,-sizeof(st),SEEK_CUR);//文件位置指针指回第二个学生数据 fwrite(&st,sizeof(st),1,fp);//修改后的第二个学生数据写回文件}fclose(fp);//关闭文件。}9.3.2基于I/O类库的文件I/O

除了用库函数进行文件输入/输出外,还可以利用C++的I/O类库进行文件的输入/输出。在利用I/O类库中的类进行外部文件的输入/输出时,程序中需要下面的包含命令:

#include<iostream> #include<fstream>

1、输出首先创建一个ofstream类(是ostream类的派生类)的对象,使之与某个外部文件建立联系。建立ofstream类的对象与外部文件联系的方式有两种:直接方式和间接方式。直接方式是在创建ofstream类的对象时指出外部文件名和打开方式,例如:

ofstreamout_file(<文件名>,<打开方式>);

间接方式是在创建了ofstream类的对象之后,调用ofstream的一个成员函数open来指出与外部文件的联系。例如: ofstreamout_file; out_file.open(<文件名>,<打开方式>);其中,<文件名>表示文件对象out_file对应的外部文件名,<打开方式>可以是:·ios::out,含义与fopen的打开方式“w”相同。·ios::app,含义与fopen的打开方式“a”相同。

另外,<打开方式>还可以是上面的值与ios::binary按位或(|)操作的结果,它表示按二进制方式打开文件。默认的方式是文本方式。例9.10用I/O类库的类实现例9.5的程序功能。在本例中,我们用类StudentScores来描述学生的成绩数据,通过重载操作符“<<”和“>>”来实现对StudentScores类的数据的输入/输出操作。

#include<iostream> #include<fstream> #include<iomanip> usingnamespacestd;constintMAX_NUM_OF_COURSES=30;constintMAX_ID_LEN=10;constintMAX_NAME_LEN=8;classStudentScores{public:StudentScores(){initialized=false;}booldata_is_ok()const{returninitialized;}private:intscores[MAX_NUM_OF_COURSES],num_of_courses;charid[MAX_ID_LEN+1],name[MAX_NAME_LEN+1];boolinitialized;//表示学生成绩数据是否被成功读入friendistream&operator>>(istream&in,StudentScores&x);friendostream&operator>>(ostream&out,StudentScores&x);}istream&operator>>(istream&in,StudentScores&x){if(&in==&cin)//从键盘输入时需要给出提示

cout<<“请输入学号、姓名、选课数及各门课成绩(以学号为‘E’结束):\n”;in>>setw(11)>>x.id;//读入学号if(in.eof()||x.id[0]==‘E’)//判断结束标记{x.initialized=false;returnin;}in>>setw(9)>>;//读入姓名in>>x.num_of_courses;//读入选课数if(x.num_of_course>MAX_NUM_OF_COURSES){x.initialized=false;returnin;}for(inti=0;i<x.num_of_courses;i++)//循环读入各门课成绩

in>>x.scores[i];x.initialized=true;returnin;}ostream&operator>>(ostream&out,StudentScores&x){out<<x.id<<‘’//输出学号

<<<<‘’//输出姓名

<<x.num_of_courses;//输出选课数for(inti=0;i<x.num_of_courses;i++)//循环输出各门课成绩out<<‘’<<x.scores[i];returnout;}intmain(){ofstreamout_file(“d:\\scores.txt”,ios::out);//以文本方式打开文件用于输出

if(!out_file)//判断文件打开是否成功

{cerr<<“打开文件失败!\n”;return-1;}StudentScoresst;cin>>st;//从标准输入设备读入第一个学生的选课信息while(st.data_is_ok())//判断输入是否结束{out_file<<st<<endl;//往文件中写入学生选课信息cin>>st;//从标准输入设备读入下一个学生的选课信息}out_file.close();//关闭文件return0;}2、输入首先创建一个ifstream类(istream类的派生类)的对象,并与外部文件建立联系。例如:

ifstreamin_file(<文件名>,<打开方式>);//以直接方式建立与外部文件的联系或

ifstreamin_file; in_file.open(<文件名>,<打开方式>);//以间接方式建立与外部文件的联系

其中,<文件名>是对象in_file对应的外部文件名,<打开方式>可以是ios::in,它的含义与fopen的打开方式“r”相同,也可以把它与ios::binary通过按位或(|)操作实现二进制打开方式。默认的方式是文本方式。 在进行输入操作前也必须对文件打开是否成功进行判断,判断方式与输出文件对象相同。

例9.11用I/O类库中的类实现例9.7中程序的功能。

#include<iostream> #include<fstream> #include<iomanip> usingnamespacestd; classStduentScores {public: StduentScores(){initialized=false;} booldata_is_ok(){returninitialized;} char*get_id()const{returnid;} constchar*get_name()const{returnname;} intaverage_score()const {inttotal=0; for(inti=0;i<num_of_courses;i++) total+=scores[i]; returntotal/num_of_courses; } private: intscores[MAX_NUM_OF_COURSES],num_of_courses;

charid[MAX_ID_LEN+1],name[MAX_NAME_LEN+1]; boolinitialized; friendistream&operator>>(istream&in,StduentScores&x); friendostream&operator<<(ostream&out,StduentScores&x); }; ……//操作符“>>”和“<<”的重载与例9.10完全相同。

intmain() {ifstreamin_file(“d:\\scores.txt”,ios::in);//以文本方式打开文件用于输入

if(!in_file)//判断文件打开是否成功

{cerr<<“打开文件失败!\n”;return-1;}cout<<“学号,姓名,平均成绩:\n”;StudentScoresst;in_file>>st;while(st.data_is_ok()){cout<<st.get_id()<<‘,’

<<st.get_name()<<‘,’

<<st.average_score()<<endl;in_file>>st;}in_file.close();//关闭文件。}3、输入/输出如果需要打开一个既能读入数据也能输出数据的文件,则需要创建一个fstream类的对象(类fstream是类iostream的派生类)。在创建fstream类的对象并建立与外部文件联系时,文件打开方式应为ios::in|ios::out(可在文件任意位置写)或ios::in|ios::app(只能在文件末尾写)。例如,下面打开的文件既能读入又能写出数据:

fstreamio_file(“d:\\test.txt”,ios::in|ios::out);

一般来说,以读写方式打开的文件,数据的读写操作要与下面介绍的seekp或seekg操作配合使用。4、随机存取文件为了能够随机读写文件中的数据,必须要显式地指出读写的位置。对于以输入方式打开的文件,可用下面的操作来指定文件内部的指针位置:istream&istream::seekg(<位置>);//指定绝对位置istream&istream::seekg(<偏移量>,<参照位置>);//指定相对位置streamposistream::tellg();//获得指针位置对于输出文件,可以用下面的操作来指定文件内部的指针位置:ostream&ostream::seekp(<位置>);//指定绝对位置ostream&ostream::seekp(<偏移量>,<参照位置>);//指定相对位置streamposostream::tellp();//获得指针位置 在上面的函数中,<参照位置>可以是ios::beg(文件头)、ios::cur(当前位置)和ios::end(文件尾)。例9.12

根据学号在例9.6的程序所生成的数据文件(students.dat)中查找某个学生信息并修改该学生的专业。

#include<iostream> #include<fstream> #include<iomanip> #include<cstring>usingnamespacestd;……//这里省略了Student、Date、Sex以及Major的定义。classStudentsFile{public:

StudentsFile(constcharfilename[]); {io_file.open(filename,ios::in|ios::out|ios::binary);} ~StudentsFile(){io_file.close();} boolis_open()const{returnio_file.is_open();}intfind(charid[],Student&st)//查找学号为id的学生

{intindex=0; io_file.seekg(0); io_file.read((char*)&st,sizeof(st));//读入第一个学生的数据

while(!io_file.eof())//循环查找学号为id的学生

{if(strcmp(st.id,id)==0) returnindex;//返回找到的学生在文件中的位置

index++; io_file.read((char*)&st,sizeof(st));//读入下一个学生的数据

} ruturn–1;//没有找到返回-1 }

boolput_at(intindex,Student&st)//更新文件中指定位置上的学生信息

{io_file.seekp(index*sizeof(st));//文件位置指针定位

if(io_file.fail())returnfalse; io_file.write((cha

温馨提示

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

评论

0/150

提交评论