第八章 IO库

文章目录

IO库

8.1 IO类

三大IO类

w前缀的为对应的宽字符版本

cincoutcerrclog都有对应的宽字符版本wcinwcoutwcerrwclog

头文件和类的关系:

  1. iostream头文件

    1. istream,wistream
    2. ostream,wostream
    3. iostream,wiostream
  2. fstream头文件

    1. ifstream,wifstream
    2. ofstream,wofstream
    3. fstream,wfstream
  3. sstream头文件

    1. istringstream,wistringstream
    2. ostringstream,wostringstream
    3. stringstream,wstringstream

IO类之间的继承关系:

第八章 IO库

8.1.1 IO对象拷贝或赋值

注意:

  1. 流对象不能进行拷贝和赋值

  2. 读写IO对象会改变流的状态,因此传递和返回的流的引用不能是const的

8.1.2 条件状态

strm指的是任意一个IO类,置位指将标志数对应位设置为1,复位指将标志数对应位设置为0

条件状态 描述
strm::iostate iostate是一种机器相关的类型,提供了条件状态的完整功能(VS2019中为int型)
strm::badbit 用来指出流已崩溃 4
strm::failbit 用来指出一个IO操作失败了 2
strm::eofbit 用来指出流到达了文件末尾 1
strm::goodbit 用来指出流未处于错误状态。此值保证为零 0
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。返回viod
s.setstate(flags) 根据给定的flags标志位,将流s中对应状态位置位。flags类型为strm::iostate。返回void
s.rdstate() 返回流的当前状态,返回值类型为strm::iostate

注意:一旦一个流发生错误,其上后续的IO操作都会失败。特别要注意的是读取文件的时候经常会读取到文件末尾,eoffail被置位,导致流失效

源文件中有一个**strm::iostate***(实质为int***)类型的_Mystate变量

_Mystate各个位的含义:

状态位 badbit failbit eofbit
位下标 7 6 5 4 3 2 1 0

函数源代码:

(1)
iostate rdstate() const {
    return _Mystate;
}

(2)
bool good() const {
    return rdstate() == ios_base::goodbit;
}

bool  eof() const {
    return rdstate() & ios_base::eofbit;
}
//剩下的几个函数以此类推...

(3)
//由下面的函数可得,想要清除哪个位就将传入值中的那个位置0
void  clear(iostate _State = goodbit) {
      clear(_State);
}
    
void clear(iostate _State) {
      _State &= _Statmask;//_Statmask = 00010111
      _Mystate             = _State;
}

(4)
void setstate(iostate _State) { 
     clear(rdstate() | _State);
}

相信你已经明白了为什么

badbit值为4[00000100~b~],failbit的值为2[00000010b],efo的值为1[00000001~b~],goobit的值为0[00000000b]

8.1.3 管理输出缓冲

每个输入输出流对象都有自己的缓冲区

关联输入输出流

当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。

标准库将cin-cout关联,将cerr-cout关联

tie有两个版本,两个版本返回的都是指向改变之前关联的对象的指针

  1. 第一个版本:不接受参数
  2. 第二个版本:接受一个指向ostream的指针,将自己关联到此ostream

我们可以将一个istream对象关联到另一个ostream,也可以将一个ostream关联到另一个ostream

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

8.2 文件输入输出

8.2.1 使用文件流对象

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

注意:

  1. 同一个流对象再次打开同一个文件会导致打开失败

  2. 不同对象可以同时打开同一个文件

  3. 当一个fstream对象被销毁时,close会自动被调用

8.2.2 文件模式

可选打开方式

mode 描述
in 以读方式打开
out 以写方式打开
app 每次写操作前均定位到文件末尾
ate 每次文件打开后立即定位到文件末尾
trunc 截断文件
binary 以二进制方式进行IO

默认打开方式

对象 默认打开方式
ifstream in
ofstream out
fstream in 和 out

文件打开方式限制:

  • 只可以对ofstream或fstream对象设定out模式
  • 之可以对ifstream或fstream对象设定in模式
  • 只有但out也被设定时才可以设定trunc模式
  • 只要trunc模式没被设定,就可以设定app模式。在app模式下,即使没有显示指定out模式,文件也总是以输出方式被打开
  • 默认情况下,即使我们没有指定trunc,以out模式打开的文件也会被截断。为了保留out模式打开的文件的内容,我们必须同时指定app模式,这样只会将数据追加写到文件末尾;或者同时指定in模式,即打开文件进行读写操作
  • ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用

8.3 string流

操作 描述
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

8.4 IO再探

8.4.1格式化输入输出

操纵符:一个操纵符是一个函数或是一个对象,会影响流的状态,并能作输入或输出运算符的运算对象

**注意:**当操作符改变流的格式状态时,通常改变后的状态对所有后续IO都生效

控制布尔值的格式

使用

std::cout<<boolalpha;

可以将布尔值以单词形式输出,要想调整回来,可以使用

std::cout<<noboolalpha;

指定整型值的进制

符号 含义
dec 十进制
oct 八进制
hex 十六进制

可使用 showbase显示不同进制的前缀,noshowbase取消不同进制的前缀显示

控制浮点数格式

可以调用IO对象的precision成员或使用setprecision操纵符来改变精度

默认情况下 ,浮点数按六位数字精度打印;

如果浮点数没有小数部分,则不会打印小数点;

根据浮点数的值选择打印成顶点十进制或科学计数法形式,标准库会选择可读性好的方式进行显示

操作符前面的*号表示此模式为默认模式

定义在iostream中的操纵符 描述
boolalpha 将true和false输出为字符串
*noboolalpha 将true和false输出为1和0
showbase 整数值输出表示进制的前缀
*noshowbase 不生成表示进制的前缀
showpoint 对浮点数总是显示小数点
*noshowpoint 只有当浮点值包含小数部分时才显示小数点
showpos 对非负数显示+[^对于unsigned类型不会显示+]
*noshowpos 对非负数不显示+
uppercase 在十六进制中打印0X,在科学计数法中打印E
*nouppercase 在十六进制中打印0x,在科学计数法中打印e
*dec 整型值显示为十进制
hex 整型值显示为十六进制
oct 整型值显示为八进制
left 在值的右侧添加填充字符
right 在值的左侧添加填充字符
internal 子符号和值的中间添加填充字符
fixed 浮点值显示为顶点十进制[^固定6位小数]
scientific 浮点值显示为科学计数法
hexfloat 浮点值显示为十六进制(C++11新特性)
*dehexfloat 重置浮点数格式为十进制(C++11新特性)
unitbuf 每次输出操作后都刷新缓冲区
*nounitbuf 恢复正常的缓冲区刷新方式
*skipws 输入运算符跳过空白符
noskipws 输入运算符不跳过空白符[^对string对象无效]
flush 刷新ostream缓冲区
ends 插入空字符,然后刷新ostream缓冲区
endl 插入换行,然后刷新ostream缓冲区

输出补白

  • setw指定下一个数字或字符串值的最小空间(setw只能作用一次)
  • left表示左对齐输出
  • right表示右对齐输出(默认)
  • internal控制负数的符号的位置,它左对齐符号,右对齐值,用空格填满所有中间的空间
  • setfill允许制定一个字符代替默认的空格来补白输出
定义在iomanip中的操纵符 描述
setfill(ch) 用ch填充空白
setprecision(s) 将浮点数精度设置为n
setw(w) 读或写值得宽度为w个字符
setbase(b) 将整数输出为b进制

8.4.2未格式化的输入\输出操作

需要了解的是,缓冲区中会有一个指针,指向我们当前操作的字符,读取或输出缓冲区内容时,指针会自动++

单字节操作

单字节操作函数 描述
is.get(ch) 从istream is读取下一个字节存入字符ch中。返回is
os.put(ch) 将字符ch输出到ostream os。返回os
is.get() 将is的下一个字符作为int返回
is.putback(ch) 将流指针后移一个字节。返回is
is.unget() 将流指针后移一个字节。返回is
is.peek() 将下一个字节作为int返回,但不移动指针位置

函数peek()和无参版本的get版本都以int类型从输入流返回一个字符。

这些函数返回一个int的原因是:可以返回文件尾标志。我们使用char范围中的值来表示一个真实字符,因此,取值范围中没有额外的值可以用来表示文件尾

多字节操作

多字节操作函数 描述
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) 将字符数组source中的最多size个字符写入os。返回os
is.ignore(size,delim) 忽略最多size个或者忽略delim前的所有字符(包括delim),哪个先满足就按哪个执行

注意:

  1. is.get()和is.getline()函数会读取size-1个字节,并自动把字符数组最后一个字节赋值为’\0’,而read函数会读取size个字节,不会自动把字符数组最后一个字节赋值为’\0’,需要我们特别注意,否则将有可能导致错误
  2. 在一台char被实现为unsignend char类型的机器上,下面的循环永远不会停止:*
char ch;
while((ch = cin.get()) != EOF){
    cout.put(ch);
}
//原因如下
//EOF = -1  ->源码:1...00000001  ->反码:1...11111110  ->补码:1...11111111
//ch取得EOF低八位,所以 ch = 11111111(二进制) -> ch = 255,而EOF = -1,所以永远不会相等

8.4.3 流随机访问

随机IO本质上是依赖于系统的,为了理解如何使用这些特性,你必须查询系统文档

注意:istream和ostream类型通常不支持随机访问

后缀g可以理解为get,p可以理解为put

随机访问函数 描述
tellg() 返回一个输入流中(tellg)标志的当前位置
tellp() 返回一个输出流中(tellp)标志的当前位置
seekg(pos) 在一个输入流中将标志重定位到给定的绝对地址。pos通常是前一个tellg返回的值
seekp(pos) 同上,只不过运用的是输出流
seekg(off,from) 在一个输入流将标志定位到from之前或之后off个字符(off表示后移,off为负表示前移)
seekp(off,from) 同上,…
from的值 描述
beg 流开始位置
cur 流当前位置
end 流结尾位置

注意:标准库区分seek和tell函数的gp版本这一特性可能会导致误解。即使标准库进行了区分,但它在一个流中之维护单一的标志——并不存在独立的读标志和写标志

上一篇:IO库


下一篇:zlib使用心得