从零学习C++第九章:输入输出

9.1 概述

  • C++中,输入/输出(input/output)是一种基于字节流(stream)的操作。
  • 以过程式的方式进行输入/输出通过C语言函数库中的输入/输出函数实现;以面向对象的方式进行输入/输出通过C++的I/O类库实现。

9.2 面向控制台的输入/输出

  • 面向控制台的输入/输出:从计算机系统的标准输入设备(键盘)输入程序所需要的数据以及把程序的计算结果或错误信息输出到计算机系统的标准输出设备或标准的错误信息输出设备(显示器、打印机等)。

 

9.2.1 基于函数库的控制台I/O

  • scanf和printf

 

9.2.2 基于类库的控制台I/O

  1. 预定义的控制台对象
  • 在I/O类库中预定义了4个I/O对象,在头文件iostream中声明
    • cin:属于istream类的对象,对应计算机系统的标准输入设备
    • cout:属于ostream对象,对应计算机系统的用于输出程序正常运行结果的标准输出设备
    • cerr、clog:输入ostream对象,对应着计算机系统的用于输出程序错误信息的设备,通常对应显示器,不受输出重定向的影响。

 

  1. 输出
  • 任何基本数据类型的数据和指针都可以通过cout、cerr、clog对象和插入操作符“<<”进行输出
  • 特例:对于指向字符串的指针进行输出
  • 操纵符(manipulator)可以对输出格式进行进一步控制,头文件插入#include<iomanip>

 

操纵符

含义

endl

输出换行符,并执行flush操作

flush

使输出缓存中的内容立即输出

dec

十进制输出

oct

八进制输出

hex

十六进制输出

setprecision (int n)

设置浮点数的精度(由输出格式决定是有效数字的个数还是小数点后数字的位数)

setiosflags (long flags)/

resetiosflags( long flags)

设置/取消输出格式,flags的取值可以是:ios::scientific(以指数形式显示浮点数)、ios::fixed(以小数形式显示浮点数)

	#include<iostream>
	#include<iomanip>
	
	int x=10;
	double f=123.456789;
	char c[]="abcd";
	char *p=c;
	cout<<p<<endl;//输出整个字符串而不是字符串的地址值
	cout<<(void*)p<<endl;//输出字符串的地址值
	cout<<setprecision(7)<<f<<endl;//设置7位有效数字

abcd
0x7ffee43787db
123.4568
  1. 输入
  • 任何基本数据类型的数据都可以通过cin对象和抽取操作符“>>”进行输入,在输入时,各数据用空白符隔开。
  • 可以使用iostream类的基于字节流的成员函数实现空白符的输入
  • 用cin的输入操作是带输入缓存的,只有当用户按“回车”时,输入的数据才会放入程序的变量中

 

9.2.3 抽取/插入操作符“>>”和“<<”的重载

  • 为了能用抽取操作符“>>”和插入操作符“<<”对自定义类的对象进行输入/输出操作,就需要对自定义的类重载抽取操作符“>>”和插入操作符“<<”。

9.3 面向文件的输入/输出

9.3.1 文件概述

  • 在外部存储器保存数据的方式有两种:文件数据库
  • 在C++中,把文件看成由一系列字节构成的字节串,称为流式文件。
  • 在文件中,数据的存储方式有两种:文本方式(text)二进制方式(binary)
    • 文本方式:用于存储具有“行”结构的文字数据,如源程序以及纯文本格式的数据等。只可包含可显示字符和有限的几个控制字符(如'\r'、'\n'、'\t'等)
    • 二进制方式:存储无显式结构的数据,数据的格式由应用程序来解释,如目标代码以及二进制数据等。可包含任意的没有显式含义的二进制字节
  • 以不同方式存储文件,对它们的读写操作是有区别的

 

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

  • 需包含的头文件:#include <cstdio>

 

  1. 文件的输出操作(往文件写数据)
    1. 打开文件
    • FILE *fopen ( const char *filename , const char *mode ); //打开文件
      1. filename:要打开的外部文件名
      2. mode:打开方式
        1. “w”:若该文件已存在,将其内容清除;否则先创建该外部文件。文件位置指针指向文件的头。
        2. “a”:若该文件已存在,从文件末尾操作;否则先创建该外部文件。文件位置指针指向文件的尾。
        3. 在打开方式“w”或“a”后加“b”,表示以二进制方式打开文件。(默认为文本方式)
    • 文件的打开后,fopen返回一个非空的“FILE *”类型的指针,该指针指向与打开的文件有关的一些信息(如文件的内存缓冲区等),它将被今后的文件输出操作函数使用。
    • 若文件打开失败,函数fopen返回空指针。

 

  1. 输出数据(往文件中写数据)
  • 往文件中写数据的函数:
    • //写入一个字符,写入成功时返回输出的字符  int fputc ( int c , FILE *stream );
    • //写入一个字符串,写入成功时返回一个非负整数  int fputs (const char *string , FILE *stream);
    • //写入基本类型数据,返回写入的字符数 int fprintf ( FILE *stream , const char *format [ , argument ] ... );
    • //按字节写入数据。参数size为字节块的尺寸;count为字节块的个数。返回实际输出的字节块的个数 (以二进制方式写入)
      • size_t fwrite ( const void *buffer , size_t size , size_t count , FILE *stream );

 

  1. 关闭文件
  • //关闭文件 int fclose ( FILE *stream );

 

  1. 文件的输入操作(从文件中读数据)
    1. 打开文件
    • FILE *fp = fopen ( const char *filename , const char *mode ); //打开文件
      • filename:要打开的外部文件名
      • mode:打开方式
        • “r”:打开一个外部文件用于读操作
        • 在打开方式“r”后加“b”,表示以二进制方式打开文件。(默认方式为文本方式)
    • 文件的打开后,fopen返回一个非空的“FILE *”类型的指针,该指针指向与打开的文件有关的一些信息(如文件的内存缓冲区等),它将被今后的文件输出操作函数使用。
    • 若文件打开失败,函数fopen返回空指针。

 

 

  1. 输入数据(从文件中读数据)
  • 从文件中读数据的函数:
    • //读一个字符,返回字符的编码 int fgetc(FILE *stream);
    • //输入一个字符串,函数正常结束时返回string的值,否则返回NULL char *fgets ( char *string , int n, FILE *stream );
    • //输入基本类型的数据,返回值表示读入并存储的数据个数 int fscanf ( FILE *stream , const char *format [, argument ] ... );
    • //按字节输入数据。参数size为字节块的尺寸;count为字节块的个数。返回值表示读入的字节的个数
      • size_t fread ( const void *buffer , size_t size , size_t count , FILE *stream );
    • //判断文件结束。当文件位置指针在文件末尾时,继续进行读操作将会使得feof返回非零(true) int feof(FILE *stream);
  • 从文件中读取数据时,必须要知道文件的存储格式,包括数据类型和存储方式,否则无法正确读取数据。

 

  1. 关闭文件
  • //关闭文件 int fclose ( FILE *stream );

 

 

  1. 文件的输入/输出操作
  • 打开一个文件,既可以读,也可以写。
    • FILE *fopen ( const char *filename ,const char *mode );
      • mode可以是:
        • “r+:读/写操作。文件必须存在
        • “w+:读写操作。若文件不存在,创建;若文件存在,清空。
        • “a+:读写操作。若文件不存在,创建;若文件存在,在文件末尾操作。

 

  1. 随机的输入/输出操作
  • 显式指定文件位置指针:
    • int fseek ( FILE *stream , long offset , int origin ); //显式指定文件位置指针的位置
      • origin指出参考位置:
        • SEEK_CUR:当前位置
        • SEEK_END:文件末尾
        • SEEK_SET:头文件
      • offset为移动的字节数(偏移量),可以为正值(往后移动)或负值(向前移动)
      • 返回值为0表示移动成功,否则失败
    • 获取位置指针的位置:
      • long ftell ( FILE *stream );

 

9.3.3 基于类库的文件I/O

  • 需包含的头文件:<iostream>和<fstream>

 

  1. 输出(向文件中写数据)
  • 创建ofstream类的对象,通过直接方式或间接方式与外部文件建立联系
    • 直接方式:ofstream out_file (<文件名>,<打开方式>)
    • 间接方式:ofstream out_file;    out_file.open(<文件名>,<打开方式>)
  • 打开方式:
    • ios::out:同fopen“w”。(默认方式)
    • ios::app:同fopen“a”。
    • |ios::binary:以二进制方式打开文件。
  • 关闭文件:
    • out_file.close( );

 

 

  1. 输入(从文件中读数据)
  • 创建ifstream类的对象,并与外部文件建立联系
    • 直接方式:ifstream in_file(<文件名>,<打开方式>);
    • 间接方式:ifstream in_file;    in_file.open(<文件名>,<打开方式>);
  • 打开方式:
    • ios::in:同fopen“r”。(默认方式)
    • |ios::binary:以二进制方式打开文件。
  • 关闭文件:
    • in_file.close( );

 

	constintMAX_NUM_OF_COURSES=30;
	constintMAX_ID_LEN=10;
	constintMAX_NAME_LEN=8;
	
	classStudentScores{
	
	private:
	intscores[MAX_NUM_OF_COURSES],num_of_courses;
	charid[MAX_ID_LEN+1],name[MAX_NAME_LEN+1];
	boolinitialized;//表示学生成绩数据是否被成功读入
	
	public:
	StudentScores();
	booldata_is_ok()const;
	intaverage_score()const;
	
	constint*getScores()const;
	
	intgetNumOfCourses()const;
	
	voidsetNumOfCourses(intnumOfCourses);
	
	constchar*getId()const;
	
	constchar*getName()const;
	
	boolisInitialized()const;
	
	voidsetInitialized(boolinitialized);
	
	friend istream &operator >> (istream &in,StudentScores &x);
	friend ostream &operator << (ostream &out,constStudentScores &x);
	};
	
	-----------------------------------------------------------------------------------------------------------------
	
	#include"StudentScores.h"
	#include<iomanip>//操纵符声明头文件
	
	StudentScores::StudentScores(){
		initialized=false;
	}
	
	boolStudentScores::data_is_ok()const{
		returninitialized;
	}
	
	istream&operator>>(istream&in,StudentScores&x){
		if(&in==&cin){//从键盘输入时需要给出提示
		cout<<"请输入学号、姓名、选课数及各门课成绩(以学号'E'结束):\n";
		}
		in>>setw(11)>>x.id;//读入学号,操纵符setw用于指定输入字符的最大个数
		if(in.eof()||x.id[0]=='E'){//判断结束标志
		x.initialized=false;
		returnin;
		}
		in>>setw(9)>>x.name;//读入姓名
		in>>x.num_of_courses;//读入选课数
		if(x.num_of_courses>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,constStudentScores&x){
		out<<x.id<<''<<x.name<<''<<x.num_of_courses;
		for(inti=0;i<x.num_of_courses;++i){
		out<<''<<x.scores[i];
		}
		returnout;
	}
	
	constint*StudentScores::getScores()const{
		returnscores;
	}
	
	intStudentScores::getNumOfCourses()const{
		returnnum_of_courses;
	}
	
	voidStudentScores::setNumOfCourses(intnumOfCourses){
		num_of_courses=numOfCourses;
	}
	
	constchar*StudentScores::getId()const{
		returnid;
	}
	
	constchar*StudentScores::getName()const{
		returnname;
	}
	
	boolStudentScores::isInitialized()const{
		returninitialized;
	}
	
	voidStudentScores::setInitialized(boolinitialized){
		StudentScores::initialized=initialized;
	}
	
	int StudentScores::average_score() const{
		int total=0;
		for(int i=0;i<num_of_courses;++i){
			total += scores[i];
		}
		return total/num_of_courses;
	}


int main(){
	StudentScoresst;
	
	ofstreamout_file("/Users/zhangzhiqiang/Desktop/test.txt");
	if(!out_file){
	cerr<<"打开文件失败!"<<endl;
	return-1;
	}
	cin>>st;//从标准输入设备读入第一个学生的选课信息
	while(st.data_is_ok()){
	out_file<<st<<endl;
	cin>>st;
	}
	out_file.close();
	
	//以文本方式打开文件用于输入
	ifstreamin_file("/Users/zhangzhiqiang/Desktop/test.txt",ios::in);
	if(!in_file){
	cerr<<"打开文件失败"<<endl;
	return-1;
	}
	cout<<"学号,姓名,平均成绩:"<<endl;
	in_file>>st;
	while(st.data_is_ok()){
	cout<<st.getId()<<","<<st.getName()<<","<<st.average_score()<<endl;
	in_file>>st;
	}
	in_file.close();
	
	return0;
}
  1. 输入/输出与随机存取
  • 打开文件:
    • fstream io_file(<文件名>,<打开方式>);
  • 打开方式:
    • ios::in | ios::app:即可读,也可写。只能在文件末尾写
    • ios::in | ios::out:即可读,也可写。可在文件任意位置写
  • 显式指定读写的位置:
    • 对于以输入方式打开的文件,指定文件内部指针位置:
      • istream& istream::seekg(<位置>);//指定绝对位置
      • istream& istream::seekg(<偏移量>,<参照位置>);//指定相对位置
      • streampos istream::tellg( );//获得指针的位置
    • 对于输出文件,指定文件内部指针位置:
      • ostream& ostream::seekp(<位置>);//指定绝对位置
      • ostream& ostream::seekp(<偏移量>,<参照位置>);//指定相对位置
      • streampos ostream::tellp( );//获得指针的位置
  • 参考位置可以是:
    • ios::beg:文件头
    • ios::cur:当前位置
    • ios::end:文件尾

9.4 面向字符串变量的输入/输出

  • 基于字符串变量的输入/输出功能的库函数主要是sscanf和sprintf:
    • int sprintf ( char *buffer ,const char *format [, argument ] .. );
    • int sscanf ( const char *buffer , const char *format [, argument ] .. );
  • 与文件输入/输出不同:这里的输入源和输出目标不是文件,而是内存中缓冲区:buffer

9.5 小结

  • 输入/输出是程序不可缺少的一部分。在C++中,输入/输出功能是以标准库的形式来提供的。
  • 输入/输出操作分为控制台I/O、文件I/O以及字符串I/O。在C++标准库中,输入/输出操作以两种形式提供:函数库和类库。
  • 利用I/O类库可以对输入/输出功能进行扩充,通过重载插入操作符“<<”和抽取操作符“>>”,程序能够方便地对用户自定义类型的数据进行输入/输出处理。
  • 文件的组织形式有两种:文本文件和二进制文件。
    • 文本文件中只包含可显示字符和有限的几个控制字符(如'\r'、'\n'、'\t'等)
    • 二进制文件中可包含任意的二进制字节
  • 在进行文件输入/输出操作时首先要打开文件,使得程序中表示文件的变量与外部的某个文件建立关联。文件操作结束后要关闭文件,把暂存在内存缓冲区的内容写入文件中,并归还打开文件时申请的资源。
  • 文件操作的基本方式主要有:顺序读/写以及添加。另外,可以通过显式指定文件位置指针的位置来实现对文件的随机读/写。

https://github.com/zzq1996/ProgrameDesign

参考:《程序设计教程:用C++语言编程》 陈家骏,郑滔

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值