标准库_IO库

一、 总述

C++使用标准库类来处理面向流的输入和输出:

  • iostream处理控制台IO。
  • fstream处理命名文件IO。
  • stringstream完成内存string的IO。
头文件类型
iostreamistream,wistream 从流读取数据。ostream,wostream 向流写入数据。iostream,wiostream 读写流。
fstreamifstream,wifstream 从文件读取数据。 ofstream,wofstream 向文件写入数据。fstream,wfstream 读写文件。
sstreamistringstream,wistringstream 从string读取数据。ostringstream,wostringstream 向string写入数据。stringstream,wstringstream 读写string。

*名字以w开头,代表宽字符,例如,wistream读宽字符。
*使用iostream,fstream,stringstream,可以不用考虑是否是宽字符类型。

二、输出缓冲

每个输出流都管理一个缓冲区,用来保存程序读写的数据。
cout<<“Hello,World!”;
文本串可能立即打印出来,也有可能被操作系统保存缓存区中,随后再打印出来。
想要立即打印出来(数据真正写到输出设备或文件)就需要刷新缓冲区。
导致缓冲刷新的原因:

  1. 程序正常结束,作为main函数的return操作的一部分,刷新缓冲区。
  2. 缓冲区满时,刷新缓冲区。
  3. 我们可以使用操作符如endl,来显示的刷新缓冲区。
    操作符flush,刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。
    例:
cout<<"Hi!"<<endl;  //输出Hi!和一个换行,然后刷新缓冲区
cout<<"hi!"<<flush; //输出hi,然后刷新缓冲区
cout<<"hi!"<<ends; //输出hi和一个空字符,然后刷新缓冲区
  1. 每个输出操作后,可以使用操作符unitbuf设置流的内部状态,来清空缓冲区。默认情况下,对cerr是设置unitbuf的,因此写到cerr的内容,都是立即刷新的。
    如果想每次输出操作后都刷新缓冲区,可以使用unitbuf操纵符。它告诉流接下来的每次写操作之后都进行一次flush操作。
    nounitbuf操作符重置流,使其恢复使用正常的系统管理的缓冲区刷新机制。
cout<<unitbuf;  //之后所有输出操作都会立即刷新缓冲区。
.........
cout<<nounitbuf;  //回到正常的缓冲方式。

如果程序崩溃,输出缓冲区不会被刷新。

  1. 一个输出流可能被关联到另一个流。默认情况下,cin和cerr都关联到cout,当读cin或写cerr都会导致cout的缓冲区被刷新。
    tie有2个重载的版本。一个版本不带参数,返回指向输出流的指针。第二个版本接受一个指向ostream的指针,将自己关联到此ostream,即x.tie(&o)将流x关联到输出流o。
cin.tie(&cout)//cin关联到cout
cin.tie(&cerr);   //cin关联到cerr,读取cin时会刷新cerr

每个流同时最多关联到一个流,但多个流可以关联到同一个ostream。

三、文件输入输出

1、可以用IO运算符(<<, >>)来读写文件,可以用getline从一个ifstream读取数据。
2、 fstream特有的操作。

fstream fstrm创建一个未绑定的文件流。
fstream fstrm(s)创建一个fstream,并打开一个名字为s的文件。s可以是string类型或者指向c风格字符串的指针
fsream fstrm(s,mode)与前一个构造函数类似,但按照指定mode打开文件
fstrm.open(s)打开名为s的文件,并将文件与fstrm绑定。等价于fstream fstrm(s)
fstrm.close()关闭与fstrm绑定的文件。返回void。
fstrm.is_open()返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭。
ifstream in(ifile);  //打开指定文件。
ofstream out;  //未绑定文件
out.open(ifile)  //打开指定文件
if(out)  //检查open是否成功,open成功,我们可以使用文件了,
.......
in.close();
out.close();

3、如果目前文件流已经关联了一个文件,为了将文件流关联到另外一个文件,必须首先关闭已经关联的文件。一旦文件成功关闭,我们可以打开新的文件。
当一个fstream对象离开作用域时,与之关联的文件会自动关闭。当一个fstream对象被销毁时,close会自动被调用。
4、文件模式(file mode)

fstream fstrm(s,mode);
in以读方式打开
out以写方式打开
app每次读写都定位到文件末尾
ate打开文件后立即定位到文件末尾
binary以二进制方式进行IO
trunc截断文件

5、每个文件流类型都定义了一个默认的文件模式,当我们未指定文件模式时,就使用默认的模式。与ifsream关联的文件默认以in模式打开;ofstream关联的默认以out模式打开。与fstream关联的文件默认以in和out模式打开。
6,、默认情况下,当我们打开一个ofstream时,文件的内容会被丢弃。阻止一个ofstream清空给定文件内容的方法是同时指定app模式。

ofstream app("file",ofstream::app);  //隐含为输出模式
ofstream app("file",ofstream::out|ofstream::app);  //两者等价

四、string流

1、sstream头文件提供了对string的操作。

istringstream从string读取数据
ostringstream向string写入数据
stringstream既可从string读数据也可向string写数据

2、stringstream特有的操作

sstream strmstrm是一个未绑定的stringstream对象
sstream strm(s)strm是一个sstream对象,保存string s 的一个拷贝。
strm.str()返回strm所保存的string的拷贝
strm.str(s)将string s拷贝到strm中,返回void

3、当我们的某些工作是对整行文本进行处理,而其他工作是处理行内的单个单词时,通常可以使用istringstream。
例:
我们的输入文件看起来可能是这样的:

morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 800555000

代码:

//成员默认为公有
struct PersonInfo{
  string name;
  vector<string> phones;
};

string line,word;     //分别保存来自输入的一行和单词
vector<PersonInfo> people;     //保存来自输入的所有记录
	while(getline(cin,line)){
		PersonInfo info;
		istringstream record(line);     //将记录绑定到刚读入的行
		record>>info.name;             //读取名字
		while(record>>word){          //读取电话号码
			info.phones.push_back(word);
			}
	people.push_back(info);
}

4、当我们逐步构造输出,希望最后一起打印时,ostringstream是很有用的。
我们使用标准的输出运算符(<<)向这些对象(类型为 ostringstream)写入数据,但这些“写入”操作实际转化为string操作,分别向这些对象中的string对象添加字符。

五、输入输出格式

总述

标准库定义了一组操纵符来修改流的格式状态。大多数改变格式状态的操纵符都是设置/复原成对的。当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO都生效。

boolalpha将true和false输出为字符串
*noboolalpha将true和false输出为1,0
showbase生成显示进制的前缀
*noshowbase不生成表示进制的前缀
showpoint对浮点数总显示小数点
*noshowbase只有当浮点值包含小数部分时才显示小数点
showpos对非负数显示+
*noshowpos对非负数不显示+
uppercase十六进制打印0X,科学计数法打印E
*nouppercase十六进制打印0x,科学计数法打印e
*dec整型值显示为十进制
hex整型值显示为十六进制
oct整型值显示为八进制
left在值的右侧填充字符
right在值的左侧填充字符
internal在符号和值之间填充字符
fixed浮点值显示为定点十进制
scientific浮点值显示科学计数法
hexfloat浮点值显示十六进制
defaultfloat重置浮点数格式为十进制
umitbuf每次输出操作后都刷新缓冲区
*nounitbuf恢复正常刷新缓冲区方式
*skipws输入运算符跳过空白符
noskipws输入运算符不跳过空白符
flush刷新打印缓冲出
ends插入空字符,然后刷新打印缓冲区
endl插入换行,然后刷新打印缓冲区
*表示默认流状态

1、控制布尔值的格式

boolalpha操纵符
noboolalpha*复原

cout<<true<<" "<<false<<endl;  //输出1 0
cout<<boolalpha<<true<<" "<<false<<endl; // 输出true false
cout<<true<<" "<<false<<endl;  //  因为改变了输出格式,还没有复原,所有输出 true false
cout<<noboolalpha;    //复原
cout<<true<<" "<<false<<endl;  //因为恢复了默认格式,所以输出 1,0

2、指定整型值的进制

默认情况下是十进制。
操纵符如下:
十六进制:hex
八进制:oct
十进制:dec
这些操纵符只影响整型运算对象,浮点值的表示形式不受影响。

cout<<20<<" "<<1024<<endl;    //输出 20 1024
cout<<hex<<20<<" "<<1024<<endl;  //14 400
cout<<oct<<20<<" "<<1024<<endl;  //24 2000
cout<<dec<<20<<" "<<1024<<endl;   //20 1024

//指定进制想要变回默认10进制,就指定它类型为10进制就可以

3、在输出中指出进制

使用showbase操纵符
noshowbase恢复默认状态。

cout<<showbase;  //打印整型时显示进制
cout<<20<<" "<<1024<<endl;    //输出 20 1024
cout<<hex<<20<<" "<<1024<<endl;  //0x14 0x400
cout<<oct<<20<<" "<<1024<<endl;  //024 02000
cout<<dec<<20<<" "<<1024<<endl;   //20 1024
cout<<noshowbase;  // 恢复流状态,不再显示整型值的进制

//默认情况下十六进制是小写打印,使用uppercase操纵符,可以变成大写。nouppercase ,变回小写
cout<<uppercase<<showbase<<hex<<20<<" "<<1024<<endl;  //0X14 0X400

4、控制浮点数格式

可以控制浮点数输出三种格式

  • 以多高精度打印浮点数。
  • 数值是打印为十六进制、定点十进制、还是科学计数法形式。
  • 对于没有小数部分的浮点值是否打印小数点。

默认情况下,

  • 浮点数按6位数字精度打印。
  • 如果浮点值没有小数部分,则不打印小数点。
  • 标准库会选择一种可读性更好的格式,来输出。

4.1、 指定打印精度

我们可以通过调用IO对象的precision成员或使用setprecision操纵符来改变精度。
setprecision操纵符定义在头文件iomanip中。

//第一种方法
cout.precision(12);
double pi=3.14156;
cout<<pi<<endl;

//第二种方法
cout<<setprecision(12);
cout<<pi<<endl;
//默认情况下精度为6,想恢复,把它设置成6即可

5、输出空白

  • setw指定下一个数字或字符串值的最小空间
  • left 表示左对齐
  • right 表示右对齐
  • internal 控制负数的符号的位置。用空格填满所有中间空间
  • setfill 允许指定一个字符代替默认的空格来补白输出
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	int i = -16;
	double d = 3.14159;
	cout << setw(12) << i <<" next" << endl;
	cout << setw(12) << d <<" next" << endl;
	cout << left<< setw(12) << i << " next" << endl
	 << setw(12) << d << " next" << endl;
	cout << right << setw(12) << i << " next" << endl
	 << setw(12) << d << " next" << endl;
	cout << internal << setw(12) << i << " next" << endl
		<< setw(12) << d << " next" << endl;
	cout << setfill('#') << setw(12) << i << " next" << endl
		<< setw(12) << d << " next" << endl<<setfill(' ');
		return 0;
}

在这里插入图片描述

六、未格式化的输入输出操作

标准库还提供了一组底层操作,支持未格式化IO,这些操作允许我们将一个流当做一个无解释的字节序列来处理

is.get(ch)读取一个字节存入字符ch,返回is
os.put(ch)将字符输出到os,返回os
is.get()将is的下一个字节作为int返回
is.putback()将字符ch放回is,返回is
is.unget()将is向后移动一个字符,返回is
is.peek()将下一个字节作为int返回,但不从流中删除它
#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	int ch;
	while (ch=cin.get())
		cout.put(ch);
	return 0;
}

#include<iostream>
#include<iomanip>
using namespace std;
int main() {
	char ch;
	while (cin.get(ch))
		cout.put(ch);
	return 0;
}

运行结果:
输入什么,就输出什么。

tellg()返回输入流中的标记的当前位置
tellp()返回输出流中的标记的当前位置
seekg(pos)重定位到给定地址
seekp(pos)重定位到给定地址
seekp(off,from)将标记定位到from之前或之后off个字符
seekg(off,from)将标记定位到from之前或之后off个字符

这些操作主要用在ofstram,ifstream,ostringstream,istringstream.
pos通常是tellg或者tellp返回的值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值