C++面向对象程序设计学习笔记(8)

C++流类库与输入输出

C++流概述

C++的输入输出流

C++中,流指的是数据从一个源流到一个目的的抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动
从流中提取数据称为输入操作,向流中添加数据称为输出操作

C++的输入输出是以字节流的形式实现的,文件和字符串也可视为有序的字节流,称为文件流及字符串流

在c++中的I/O流类库中包含了许多用于输入输出的类,称为流类,用流类定义的对象称为流对象

用于输入输出的流对象

C++编译系统提供了用于输入输出的iostream类库,
常用的头文件有

iostream //包含了对输入输出流进行操作所需的基本信息,使用cin、cout等流对象进行针对标准设备的I/O操作时,需包含此头文件
fstream  //用于用户管理文件的I/O操作。使用文件流对象进行针对磁盘文件的操作时,需包含此头文件
strstream//用于字符串流的I/O操作。使用字符串流对象进行针对内存字符串空间的I/O操作时,需包含此头文件
iomanip  //用于输入输出的格式控制。在使用setw、fixed等大多数操作符进行格式控制时,需包含此头文件
用于输入输出的流类

I/O类库中常用流类

类名 说明 头文件
ios 流基类 iostream
istream 通用输入流类和其他输入流的基类 iostream
ostream 通用输出流类和其他输出流的基类 iostream
iostream 通用输入输出流类和其他输入输出流的基类 iostream
ifstream 输入文件流类 fstream
ofstream 输出文件流类 fstream
fstream 输入输出文件流类 fstream
istrstream 输入字符串流类 strstream
ostrstream 输出字符串流类 strstream
strstream 输入输出字符串流类 strstream
预定义的流对象

用流类定义的对象称为流对象,与输入设备相联系的流对象称为输入流对象,与输出设备相联系的流对象称为输出流对象

C++包含标准输入流对象cin、标准输出流对象cout、非缓冲型的标准出错流对象cerr和缓冲型的标准出错流对象clog等预定义的流对象

cerr和clog的区别是,cerr不经过缓冲区,直接向显示设备输出有关关系,clog的信息存放在缓冲区中,当缓冲区满后或遇上endl时向显示设备输出

输入输出流的成员函数

C++程序中除了用cout和插入运算符"<<"实现输出,用cin和提取运算符">>"实现输入为,还存在一些成员函数

put函数

put函数用于输出一个字符,格式如下cout.put(char c)

cout.put('A');
cout<<'A'; 

输出结果为
AA
get函数

get函数功能与提取运算符">>"类似,不同在于get函数在读入数据时可包括空白字符,而提取运算符在默认情况下拒绝接受空白字符
格式为cin.get(ch)

作用为从输入流中读取一个字符(包括空白符),赋给字符变量ch,成功返回非0值,失败返回0值

char a,b;
cin>>a;
cin.get(b);
cout<<a<<' '<<b<<endl;

当输入aa时,文件输出
a a

getline函数

getline调用形式为

cin.getline(字符数组,字符个数n,终止标示符);
或
cin.getline(字符指针,字符个数n,终止标示符);

用于从输入流中读入n-1个字符,赋给相应的字符数组或字符指针,若读入过程中遇见指定的终止字符,则提前终止输入,最后插入字符串终止标志'\n'

注意
1.cin.getline只能用于输入字符型数据
2.cin.getline可以读入包括空格符在内的一系列字符

char s[100005];
cin.getline(s,10); //输入:aahcihbiuah
cout<<s<<endl;     //输出:aahcihbiu
cin.getline(s,5,'\0');  //输入:123456
cout<<s<<endl;          //输出:1234
cin.getline(s,5,'2');  //输入:123456
cout<<s<<endl;          //输出:1
cin.getline(s,13,'a');  //输入:123456789 1234
cout<<s<<endl;          //输出:123456789 12
ignore函数

调用形式为cin.ignore(n,终止字符)
ignore函数的功能时跳过输入流中的n个字符(默认为1),或在遇到指定终止字符(默认为EOF)时提前结束

char s[100005];
cin.ignore(10); //输入:aahcihbiuah
cin>>s;
cout<<s<<endl;  //输出:h
cin.ignore(10,'h'); //输入:aahcihbiuah
cin>>s;
cout<<s<<endl;  //输出:cihbiuah

预定义类型的输入输出

预定义类型的输入输出指C++预定义标准类型的输入输出

插入运算符与提取运算符

一般使用格式为

cin>>变量;	//输入
cout<<变量;	//输出
插入运算符"<<"

插入运算符"<<"本身为左移运算符,在iostream中进行了重载,其原型为

ostream &operator<<(ostream &类型名)
提取运算符">>"

提取运算符">>"本身为右移运算符,在iostream中进行了重载,其原型为

istream &operator>>(istream &类型名)

注意:
默认情况下,运算符">>"将跳过空白符

输入输出的格式控制

C++提供两类输入输出的格式控制的方法,
一种为使用ios类中有关格式控制的流成员函数进行格式控制,另一种是使用称为操纵符的特殊类型函数进行格式控制

使用流成员函数进行格式控制

用于控制输入输出的流成员函数

流成员函数 功能
setf(flags) 设置状态标志
unsetf(flags) 清楚状态标志
width(n) 设置字段域宽为n位
fill(char ch) 设置填充字符ch
precision(n) 设置实数精度为n位,在普通十进制小数形式输出时n代表有效数字,在fixed(固定小数位数)或scientific(指数)形式输出时n代表小数位数

状态标志在类ios中被定义为枚举值,所以在引用时前要加"ios::"

状态标志 功能 输入/输出
ios::skipws 跳过输入中的空白符 输入
ios::left 输出数据在本域宽范围内左对齐 输入
ios::right 输出数据在本域宽范围内右对齐 输入
ios::internal 数据符号位左对齐,数据本身右对齐 ,符号和数据之间为填充符 输入
ios::dec 设置整数基数为10 输入/输出
ios::oct 设置整数基数为8 输入/输出
ios::hex 设置整数基数为16 输入/输出
ios::showbase 输出整数时显示基数符号(八进制以0打头,十六进制以0x打头) 输入/输出
ios::showpoint 浮点数输出时带有小数点 输出
ios::uppercase 以科学表示法格式E和以十六进制输出字符时用大写表示 输出
ios::showpos 正整数前显示'+'符号 输出
ios::scientific 用科学表示法显示浮点数 输出
ios::fixed 用定点格式显示浮点数 输出
ios::unitbuf 完成输出操作后立即刷新所有的流 输出
ios::stdio 完成输出操作后立即刷新stdout和stderr 输出

1.设置状态标示的一般格式为

流对象.setf(ios::状态标志);

注意:
1.由于状态标志在类ios中被定义为枚举值,所以在引用时前要加"ios::"
2.在设置多项标示时,中间应使用或运算符'|'分隔

2.清除状态标示的一般格式为

流对象.unsetf(ios::状态标志);

3.设置域宽的一般格式为

流对象.width(int n);

注意:每次设置的域宽只对下一次操作有效,每次操作结束后,域宽回复为默认域宽0

4.设置实数精度的一般格式为

流对象.width(int n);

设置实数精度为n位,在普通十进制小数形式输出时n代表有效数字,在fixed(固定小数位数)或scientific(指数)形式输出时n代表小数位数

例:

    cout.setf(ios::right | ios::fixed);
    cout.width(10);
    cout<<"1234"<<endl; //域宽为10
    cout<<"1234"<<endl; //域宽为0
    double PI=acos(-1.0);
    cout.precision(10);
    cout<<PI<<endl; //固定小数位数形式
    cout.unsetf(ios::fixed);
    cout<<PI<<endl; //普通十进制小数形式
    cout.setf(ios::scientific);
    cout<<PI<<endl; //指数形式

   	输出结果
	   	      1234
	1234
	3.1415926536
	3.141592654
	3.1415926536e+000

5.填充字符的一般格式为

流对象.fill(char c);

作用为当域宽不满时输出字符c来填充,默认状态下为空格

例:

    cout.setf(ios::right | ios::fixed);
    cout.width(10);
    cout.fill('c');
    cout<<1<<endl;

    输出结果
    ccccccccc1
使用操纵符进行格式控制

C++除了可以使用ios类中有关格式控制的流成员函数进行格式控制,还可以使用称为操纵符的特殊类型函数进行格式控制。

所有不带形参的操纵符都定义在头文件iostream.h上,带形参的则定义在头文件iomanip.h上

C++预定义的操纵符

操纵符 功能 输入/输出
ws 跳过输入开头的空白符 输入
endl 输出换行符并刷新输出流 输出
ends 插入一个空字符null 输出
flush 刷新输出流 输出
dec 设置整数基数为10 输入/输出
oct 设置整数基数为8 输入/输出
hex 设置整数基数为16 输入/输出
setbase(n) 设置整数基数为n(n=0,8,10,16),默认为0,即以十进制输出 输入/输出
setfill(c) 设置填充字符c,默认为空格 输出
setprecision(n) 设置实数精度为n位,在普通十进制小数形式输出时n代表有效数字,在fixed(固定小数位数)或scientific(指数)形式输出时n代表小数位数 输出
setw(n) 设置字段域宽为n位 输出
setiosflags(f) 设置状态标志f 输入/输出
resetiosflags(f) 清除状态标志f 输入/输出
操纵符 功能
setiosflags(ios::left) 输出数据在本域宽范围内左对齐
setiosflags(ios::right) 输出数据在本域宽范围内右对齐
setiosflags(ios::fixed) 用定点格式显示浮点数
setiosflags(ios::scientific) 用科学表示法显示浮点数
setiosflags(ios::showpos) 正整数前显示'+'符号
setiosflags(ios::uppercase) 以科学表示法格式E和以十六进制输出字符时用大写表示

    cout<<setw(10)<<1234<<2345<<endl;
    cout<<setprecision(10)<<setiosflags(ios::fixed)<<acos(-1.0)<<endl;
    cout<<setprecision(10)<<acos(-1.0)<<endl;
    cout<<setprecision(10)<<resetiosflags(ios::fixed)<<acos(-1.0)<<endl;
    cout<<setw(10)<<setfill('c')<<1234<<endl;
    

    输出结果
          12342345
	3.1415926536
	3.1415926536
	3.141592654
	cccccc1234
使用用户自定义操纵符进行格式控制

如为输出流定义操纵符函数,形式如下

ostream &操纵符名 (ostream &stream)
{
	自定义代码
	return stream;
}

如为输如流定义操纵符函数,形式如下

istream &操纵符名 (istream &stream)
{
	自定义代码
	return stream;
}


ostream &outputd(ostream &stream)
{
    stream<<setprecision(10)<<setiosflags(ios::fixed);
    return stream;
}
int main()
{
    cout<<outputd<<acos(-1.0)<<endl;
    return 0;
}

输出结果为
3.1415926536

用户自定义类型的输入输出

C++通过重载运算符">>"和"<<"来实现用户自定义类型的输入输出

重载插入运算符

定义插入运算符"<<"重载函数的一般格式如下

ostream &operator<< (ostream &out,user_name& obj)
{
	out<<obj.item1;
	......
	out<<obj.itemn;
	return out;
}

user_name为用户自定义的类型名,out是ostream类对象的引用,obj为用户自定义的类型名user_name的引用,item1、.......itemn为用户自定义类型中的数据成员
重载插入运算符函数不能是所操作的类的成员函数,但可以是该类的友元函数或普通函数

重载提取运算符

定义提取运算符">>"重载函数的一般格式如下

istream &operator>> (istream &in,user_name& obj)
{
	in>>obj.item1;
	......
	in>>obj.itemn;
	return in;
}

user_name为用户自定义的类型名,in是istream类对象的引用,obj为用户自定义的类型名user_name的引用,item1、.......itemn为用户自定义类型中的数据成员
重载提取运算符函数不能是所操作的类的成员函数,但可以是该类的友元函数或普通函数

文件的输入输出

C++将文件是为字符序列,即文件是由一个一个字符数据顺序组成的,根据数据的组织形式,文件可以分为文本文件和二进制文件。文本文件又称ASCII文件,他的每个字节存放一个ASCII代码,代表一个字符。二进制文件则是把内存中的数据,按其在内存中的存储形式原样写到磁盘中存储。

C++中引入流式文件的概念,即文件一律视为字符构成的序列,即字符流

文件的打开与关闭

C++中要进行文件的操作,首先要创造一个流对象,然后将这个流对象与文件相关联,即打开文件,此后才能进行文件的读写操作,最后关闭文件。

文件的打开

c++打开一个文件,即建立一个流对象与文件相关联,关闭一个文件,就是取消这种关联

用于文件输入输出的文件流类

类名 说明 功能
ifstream 输入文件流类 用于文件输入
ofstream 输出文件流类 用于文件输出
fstream 输入输出文件流类 用于文件输出/输入

头文件为fstream.h

使用open函数打开文件的一般形式

文件流对象.open(文件名,打开方式);

文件名可包括路径,默认路径为当前目录
打开方式见下表

方式 功能
ios::app 打开一个输出文件,用于将数据添加至文件尾部
ios::ate 打开一个现存文件,将文件指针移至文件末尾
ios::in 打开一文件,以便进行输入
ios::nocreate 打开一个文件,若文件不存在,则打开失败
ios::noreplace 打开一个文件,若文件存在,则打开失败
ios::out 打开一文件,以便进行输出
ios::trunc 打开一个文件,若文件存在,则删除其中所有数据,如不存在,则建立新文件
ios::binary 以二进制方式打开一个文件,默认问文本文件

注意:
1.使用"ios::app"时,文件必须存在,打开时文件指针位于文件末尾,此方式只能用于输出
2.使用"ios::ate"时,打开时文件指针位于文件末尾,数据可写入文件任意位置
3.使用"ios::in"时,文件必须存在,此方式只能用于输入,使用ifstream时默认使用该方式
使用"ios::out"时,此方式只能用于输出,使用ofstream时默认使用该方式
4.新版本I/O类库中不提供ios::nocreate 与 ios::noreplace
5.若指定"ios::out"方式,且未指定"ios::ate"或"ios::app"方式,则隐含"ios::trunc"方式
6.当文件需要使用多种方式打开时,使用"|"操作符组合多种方式
7.可以通过定义文件流对象时指定参数,调用构造函数来实现打开文件功能
8.当文件打开操作失败,流对象的值为0

文件的关闭

使用close函数关闭文件,即将文件与文件流对象脱钩

使用close函数关闭文件的一般形式

文件流对象.close();

例: 使用文件流输出字符串

    string a="1dascipan";
    ofstream out;
    out.open("1.txt",ios::out);
    out<<a<<endl;
    out.close();
二进制文件的读写

二进制文件的读写大致与文件读写一致,但要求在打开文件使用ios::binary以二进制形式传送和存储

二进制文件进行读写有两种方式,一是使用函数getput,另一种是使用函数readwrite

1.使用函数getput

例: 使用二进制方式编写一个二进制文件并读取

void bt_wirte()
{
    ofstream outb("out.dat",ios::binary);
    for(char i='a';i<='z';i++) outb.put(i);
    outb.close();
}

void bt_read()
{
    ifstream inb("out.dat",ios::binary);
    char c;
    while(inb.get(c)) cout<<c;
    cout<<endl;
    inb.close();
}

int main()
{
    bt_wirte();
    bt_read();
    return 0;
}

输出结果
屏幕输出
abcdefghijklmnopqrstuvwxyz
并输出一个名为out.dat的二进制文件

2.使用函数readwrite
c++提供了函数readwrite用于读写一个数据块
调用格式如下

inf.read(char *buf,int len);
outf.write(const char *buf,int len);

read是流类istream中的成员函数,有两个参数,第一个参数buf为指针,指向读入数据存储空间的起始地址,第二个参数len为读入字节数。read的功能是从inf关联的文件中读取len个或读至EOF的字节,将其存入buf指向的内存空间中

write是流类ostream中的成员函数,有两个参数,第一个参数buf为指针,指向数据存储空间的起始地址,第二个参数len为输出字节数。read的功能是将其存入buf指向的内存空间中字节开始的len个字节的数据写入outf所关联的文件中

注意:
指针默认的数据类型为char * ,若为其他数据类型,则需要进行转换,并通过sizeof函数确定读入字符数

例:

void bt_wirte()
{
    char s[100]="why";
    ofstream outb("out.dat",ios::binary);
    outb.write((char *)&s,sizeof(s));
    outb.close();
}

void bt_read()
{
    char s[100];
    ifstream inb("out.dat",ios::binary);
    inb.read((char *)&s,sizeof(s));
    cout<<s<<endl;
    inb.close();
}

int main()
{
    bt_wirte();
    bt_read();
    return 0;
}

输出结果
屏幕输出
why
并输出一个名为out.dat的二进制文件

3.检测文件结束
采用文件流读写文件时,可通过成员函数eof()实现检测文件结束
一般形式为

ifstream inf;
......
if(!inf.eof()) ......

当返回值为零时,表示为到达文件尾,非零时,表示到达文件尾

也可通过检测文件流对象是否为零,若为零则表示文件结束

4.二进制文件的随机读取
前面的文件操作是按一定顺序来进行读写的,因此称为顺序文件,C++在类istream和类ostream定义了几个与文件指针相关的成员函数,使其能实现文件的随机读取

istream

tellg();				//返回输入文件读指针的位置
seekg(文件中的位置);		//将输入文件读指针移至指定的位置
seekg(位移量,参照位置);	//以参照位置为基准移动若干字节

文件中的位置和位移量都是long型整数,以字节为单位,
参照位置可为

ios::beg		//文件开头
ios::cur		//文件指针当前位置
ios::end 		//文件末尾

ostream

tellp();				//返回输出文件读指针的位置
seekp(文件中的位置);		//将输出文件读指针移至指定的位置
seekp(位移量,参照位置);	//以参照位置为基准移动若干字节

seekgseekg的第二个参数可以省略,此时参照位置为ios::beg

若为即可输出也可输入的文件,则seekgseekg都可使用

命名空间和头文件命名规则

命名空间

命名空间实际上是一个由程序设计者命名的内存区域,程序设计者可根据需要指定一些有名字的命名空间,将各命名空间中声明的标识符与该命名空间标识符相关联。

声明命名空间的一般形式为

namespace NS
{
	.......
}

namespace是定义命名空间必须的关键字,NS 是命名空间的名字,花括号为命名空间的作用域

posted @ 2019-12-22 20:35  springfield_psk  阅读(363)  评论(0编辑  收藏  举报