C++ I/O库学习

IO库
C++不直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO。这些类型支持从设备读取数据、向设备写入数据的IO操作,设备可以是文件、控制台窗口等。还有一些类型允许内存IO,从string读取数据,向string写入数据。

IO库定义了读写内置类型值得操作。此外,一些类,如string,通常也会定义类似的IO操作,来读写自己的对象。

初学C++时,为了控制台的交互,往往会接触到IO的内容,现在可以对以下的设施进行说明了:

  • istream类型,提供输入操作
  • ostream类型,提供输出操作
  • cin,istream对象,从标准输入读取数据
  • cout,ostream对象,向标准输出写入数据
  • cerr,ostream对象,用于输出程序错误信息,写入到标准错误
  • >>运算符,从一个istream对象读取输入数据
  • <<运算符,向一个ostream对象写入输出数据
  • getline函数,从给定的istream读取一行数据,存入一个给定的string对象中。

1.IO类

头文件类型
iostreamIstream, wistream从流读取数据
ostream,wostream向流写入数据
iostream,wiostream读写流
fstreamifstream,wifstream从文件读取数据
ofstream, wofstream向文件写入数据
fstream,wfstream读写文件
sstreamIstringstream, wistringstream从string读取数据
ostringstream,wostringstream向string写入数据
stringstream,wstringstream读写string

w是宽字符版本,wcin,wcout,wcerr对应cin,cout,cerr的宽字符版本对象。

1.1 IO对象无拷贝或赋值

不能拷贝和对IO对象赋值:

ofstream out1, out2;
out1 = out2;	//错误:不能对流对象赋值
ofstream print(ofstream);	//错误:不能初始化ofstream参数
out2 = print(out2);	//错误:不能拷贝流对象

所以形参和返回类型都不能设置成流类型,IO操作的函数往往以引用的方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的

1.2 条件状态

strm::iostatestrm是一种IO类型。iostate是一种机器相关的类型,提供了表达条件状态的完整功能。
strm::badbitstrm::badbit用来指出流已崩溃
strm::failbitstrm::failbit用来指出一个IO操作失败了
strm::eofbitstrm::eofbit用来指出流到达了文件结束
strm::goodbitstrm::goodbit用来指出流未处于错误状态。此值保证为零
s.eof()若流s的eofbit置位,则返回true
s.fail()若流s的failbit或badbit置位,则返回true
s.bad()若流s的badbit置位,则返回true
s.good()若流s处于有效状态,则返回true
s.clear()将流s中所有条件状态位复位,将流的状态设置为有效。返回void
s.clear(flags)根据给定的flags标志位,将流s中对应条件状态位复位。flags的类型为strm::iostate。返回void
s.setstate(flags)根据给定的flags标志位,将流s中对应条件状态位置位。flags的类型为strm::iostate,返回void
s.rdstate()返回流s的当前条件状态,返回值类型为strm::iostate

一个流一旦发生错误,后续的IO操作都会失败。只有当流处于无错状态时,才可以进行读写。
badbit无法恢复,failbit可以修正。如果badbit,failbit和eofbit的任意一个被置位,则检测流状态的条件会失败。它们有对应的函数来查询。

1.3 输出缓冲

每个输出流都管理一个缓冲区,保存读写数据。组合多个输出操作成单一的设备写操作可以提升性能。
缓冲刷新的契机:

  • 程序正常结束
  • 缓冲区满,会刷新缓冲
  • 使用操纵符如endl和flush,显式刷新缓冲
  • 每个输出操作之后,可以用操纵符unitbuf设置流的内部状态,清空缓冲区。默认清空下,对cerr是设置unitbuf的,因此写到cerr的内容都是立即刷新的。
  • 一个输出流可能被关联到另一个流。此时,读写被关联的流时,关联到的流的缓冲区会被刷新。例如默认清空下,cin和cerr都关联到cout。因此,读cin或写cerr都会导致cout的缓冲区被刷新
cout << "hi!" << endl;	//输出hi和一个换行,刷新缓冲区
cout << "hi!" << flush;	//输出hi,刷新缓冲区

cout << unitbuf;	//所有输出操作后都会立即刷新缓冲区
cout << nounitbuf;	//回到正常的缓冲方式

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

2.文件输入输出

实际上ifstream和ofstream继承于istream和ostream,所以操作和iostream差不多,它们还额外支持一些新的操作,用来管理与流关联的文件。

fstream fstrm;创建一个未绑定的文件流。fstream是头文件fstream中定义的一个类型
fstream fstrm(s);创建一个fstream,并打开名为s的文件。s可以是string类型,或者是一个指向C风格字符串的指针。这些构造函数都是explicit的。默认的文件模式mode依赖于fstream类型。
fstream fstrm(s, mode);与前一个构造函数类似,但按指定mode打开文件
fstrm.open(s)打开名为s的文件,并将文件与fstrm绑定。s可以是一个string或C风格字符串指针。默认文件mode依赖于fstream类型。返回void
fstrm.close()关闭与fstrm绑定的文件。返回void
fstrm.is_open()返回一个bool值,指出与fstrm关联的文件是否成功打开并且尚未关闭

读写一个文件,需要自己定义文件流对象,建立关联。

文件模式:

  • in: 读方式打开
  • out:写方式打开
  • app:每次写操作前均定位到文件末尾
  • ate:打开文件后立即定位到文件末尾
  • trunc:截断文件
  • binary:二进制方式进行IO
    各种模式的指定都有一些条件,比如对ifstream还是ofstream的亲和性,以及是否互相依赖、互斥等等。

3. string 流

istringstreamostringstream专门负责对string的读写。也是istream和ostream的继承类。所以,除了雷同的常规操作以外,它们也有自己独有的操作:

sstream strm;strm是一个未绑定的stringstream对象。sstream是头文件sstream中定义的一个类型
sstream strm(s);strm是一个sstream对象,保存string s的一个拷贝。次构造函数是explicit的。
strm.str()返回strm所保存的string的拷贝
strm.str(s)将string s拷贝到strm中。返回void

4 格式化输入和输出

除了条件状态外,每个iostream对象还维护着一个格式状态来控制IO格式化细节。

标准库定义了一组操纵符来修改流的格式状态。操纵符是一个函数或对象,会影响流的状态,并能作为输入和输出运算符的运算对象。类似输入和输出运算符,操纵符也返回它所处理的流对象,因此我们可以在一条语句中组合操纵符和数据。

endl就是一种操纵符,写到输出流意味着换行并刷新缓冲区的操作。

操纵符用于两大类输出控制:控制数值的输出格式控制补白的数量和位置。大多数改变格式状态的操纵符都是设置/复原成对的,一个操纵符用于设置新格式,另一个用于恢复正常格式。
当操纵符改变流的格式状态时,通常改变后的状态对所有后续IO都生效。

4.1 控制布尔值格式

bool值默认打印0或1,可以对流使用boolalpha来操纵覆盖这种格式:

cout << "default bool values: " << true << " " << false
	<< "\nalpha bool values: " << boolalpha
	<< true << " " << false << endl;

前者输出1和0,后者输出字符串true和false。

取消cout格式的改变,可以用noboolalpha

bool bool_val = get_status();
cout << boolalpha << bool_val << noboolalpha;

4.2 指定整型值的进制

默认输出十进制,可以用hex、oct和dec改为十六进制、八进制和十进制。(只影响整型)

cout << "default: " << 20 << " " << 1024 << endl;
cout << "octal: " << oct << 20 << " " << 1024 << endl;
cout << "hex: " << hex << 20 << " " << 1024 << endl;
cout << "decimal: " << dec << 20 << " " << 1024 << endl;

4.3 输出中指出进制

showbase操纵符可以指示输出的整型数显示是何种进制,其中0x前导表示十六进制,0前导表示八进制,无前导表示十进制。

操纵符noshowbase恢复。

4.4 控制浮点数格式

浮点数的输出格式涉及三个方面:

  1. 输出精度(即输出多少个数字)。
  2. 十六进制、定点十进制或者科学记数法形式输出。
  3. 没有小数部分的浮点值是否输出小数点。
    默认情况下,浮点值按六位数字精度输出;如果浮点值没有小数部分,则不输出小数点;根据浮点数的值选择输出为定点十进制或科学计数法形式:非常大或非常小的值输出为科学记数法形式,其他值输出为定点十进制形式。

默认情况下,精度控制输出的数字总位数。输出时,浮点值按照当前精度四舍五入而非截断。
调用IO对象的precision成员或者使用setprecision操纵符可以改变精度。

  • precision成员是重载的。一个版本接受一个int值,将精度设置为此值,并返回旧精度值。另一个版本不接受参数,直接返回当前精度值。
  • setprecision操纵符接受一个参数来设置精度。

setprecision操纵符和其他接受参数的操纵符都定义在头文件iomanip中。

// cout.precision返回当前精度值
cout << "Precision: " << cout.precision()
    << ", Value: " << sqrt(2.0) << endl;
// cout.precision(12)将打印精度设置为12位数字
cout.precision(12);
cout << "Precision: " << cout.precision()
    << ", Value: " << sqrt(2.0) << endl;
// 另一种设置精度的方法是使用setprecision操纵符
cout << setprecision(3);
cout << "Precision: " << cout.precision()
    << ", Value: " << sqrt(2.0) << endl;

iostream中的操纵符

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

定义在iomanip中的操纵符

setfill(ch)用ch填充空白
setprecision(n)浮点精度设置为n
setw(w)读写值的宽度为w个字符
setbase(b)将整数输出为b进制

5 未格式化的IO操作

标准库还提供了一组低层操作,支持未格式化IO。允许将一个流作一个无解释的字节序列来处理。
操作分两类,单字节操作和多字节操作。

单字节低层IO操作

is.get(ch)从istream is读取下一个字节存入字符ch中。返回is
os.put(ch)将字符ch输出到ostream os。返回os
is.get()将is的下一个字节作为int返回
is.putback(ch)将字符ch放回is。返回is
is.unget()将is向后移动一个字节。返回is
is.peek()将下一个字节作为int返回,但不从流中删除它

多字节低层IO操作

is.get(sink, size, delim)从is中读取最多size个字节,并保存在字符数组中,字符数组的起始地址由sink给出。读取过程直至遇到字符delim或读取了size个字节或遇到文件尾时停止。如果遇到了delim,则将其留在输入流中,不读取出来存入sink
is.getline(sink,size,delim)与接受三个参数的get版本莱斯,但会读取并丢弃delim
is.read(sink, size)读取最多size个字节,存入字符数组sink中。返回is
is.gcount()返回上一个未格式化读取操作从is读取的字节数
os.write(source, size)将字符数组source中的size个字节写入os。返回os
is.ignore(size, delim)读取并忽略最多size个字符,包括delim。与其他未格式化函数不同,ignore有默认参数:size默认值为1,delim默认值为文件尾
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值