YaoCheng8667 的个人博客 YaoCheng8667 的个人博客

记录精彩的程序人生

目录
《C++ Primer》第八章:IO类
/    

《C++ Primer》第八章:IO类

1. IO 类简介

1.1 IO 库类型和头文件

1. <iostream>

  • istream,wstream: 从流读取数据。
  • ostream,wostream:向流写入数据。
  • iostream,wiostream:读写流

2. <fstream>

  • ifstream,wifstream: 从文件读取数据。
  • ofstream,wofstream:向文件写入数据。
  • fstream,wfstream: 读写文件。

3. <sstream>

  • istringstream,wistringstream: 从 string 读取数据。
  • ostringstream,wostringstream: 向 string 写入数据。
  • stringstream,wstringstream: 读写 string。

为了支持宽字符语言,定义了一组类型和对象可以操作 wchar_t 类型的数据。宽字符版本的类型和函数名字以一个 w 开始。

类型之间关系:ifstream 和 istringstream 均继承自 istream。

1.2 IO 对象无拷贝和赋值

IO 对象无拷贝和赋值,因此也无法将 IO 对象设为形参和返回值。

1.3 IO 条件状态

  • strm:: iostate : 表示当前 IO 的状态。
  • strm:: badbit : badbit 用来指出流已经崩溃。
  • strm:: failedbit: 用来指出一个 IO 操作失败了。
  • strm:: eofbit: 用来指出流到达了文件末尾。

badbit 置位后流不可用,通常为系统级错误,如不可恢复的读写。failedbit 置位表示当前读写操作失败,流可能可以继续使用。

可以使用以下函数获取流的状态:

s.eof();          //是否到达文件结束。
s.failed();       //failedbit或badbit置位时返回true。
s.bad();          //badbit置位时返回true。
s.good();         //流有效时返回true。

判断一个流是否有效的最简单的方法是将其作为一个条件使用。

while(cin>>word)
	//do something

这句话的含义是若流输 word 操作成功且之后流处于有效状态,返回 true。

此外,对于流的状态,还可以进行读取和设置。

s.clear();          //将流中所有状态标志复位,流置为有效。
s.clear(flags);     //将指定状态位复位,flags类型为strm::iostate。
s.setstate(flags);  //根据指定的flags标志位,将流对应的条件状态置位。
s.rdstate();        //返回当前流的状态,返回类型为strm::iostate。

例如:以下代码将 failbit 和 badbit 复位,保持其他标志位不变。

s.clear(cin.rdstate() & ~cin.failedbit & ~cin.badbit);
//failedbit和badbit从位上来看就是相应bit置1,其余bit全0的数

1.4 管理输入输出缓冲

每个输出流都有一个缓冲区,用来保存程序读写的数据。
导致输出缓冲刷新的原因有很多:

  • 程序正常结束。
  • 缓冲区已满。
  • 使用 endl,ends,flush 显式刷新缓冲区。
  • 当一个输出流关联到一个流时(如 cout 关联到 cin 和 cerr),当读写被关联的流时,输出流缓冲均会刷新。
  • 若想每次操作均刷新缓冲区,可以使用 unitbuf 操作符。他告诉流接下来每次写操作均要进行刷新操作。如:cout<<unitbuf;。取消则为:cout << nonunitbuf;

1.5 关联输入输出流

可以使用 tie 函数关联输入输出流,通常在交互式系统中比较常用,返回值是执行之前该流关联的流。

cin.tie(&cout);
ostream* old_tie = cin.tie(nullptr);
cin.tie(&cerr);
cin.tie(old_tie);

2. 文件输入输出

2.1 使用文件流对象

创建文件流对象时,我们可以选择提供文件名也可以不提供。区别是提供文件名后 open 函数会被自动调用。

ifstream in(infile);           //infile可为string类型或c风格字符串
ofstream out;

2.2 open()和 close()

  • open 主要作用是将流与文件建立关联。
    若 open 失败则 failedbit 会被置位,对一个已经 open 的流再 open 也会导致失败。若 open 成功会设置流的状态,使得 good()变为 true。

    ifstream in(file1);
    //下面两行代码与上面一句等价
    ifstream in;
    in.open(file1);
    
  • close()为关闭文件与流的关联,close 后的流可以关联新的文件。

    in.close();
    in.open(ifile+"2");
    
  • fstream 对象拥有自动构造和析构的功能。
    当 stream 对象离开其作用域后,会自动调用 close()函数并销毁对象。如,考虑一个程序,main 函数会接受一个处理文件的列表,可能会产生如下循环。

    for(auto p = argv + 1 ;p < argv+argc; ++p){
    	ifstream in(*p);
    	if(in){
    		//do someting
    	}else
    		cerr << "can not open: " + string(*p); 
    } //每个循环in都会离开其作用域被销毁,并在下一个循环被重新创建。
    

2.3 文件模式

文件模式及其意义:

文件模式 意义
in 以只读方式打开
out 以只写形式打开
app 每次写操作前定位到文件末尾
ate 打开文件后立刻定位到文件末尾
trunc 截断文件
binary 以二进制方式进行 IO

Tips:

  1. ofstream 会自动丢弃文件内容,若要保持文件内容保留,可以设置为 append 模式。
    ofstream out("file1",ofstream::app);  
    
  2. 每次在执行 open 操作时都可以指定其文件模式。

3. string 流

3.1 stringstream 特有操作

stringstream strm(s);             //构造函数,传入的参数为string
strm.str();                       //返回strm保存的string的拷贝
strm.str(s);                      //将string s拷贝到strm中,返回值为void

3.2 istringstream

istringstream 常用于对整行数据进行处理。如,对于以下统计电话号码的程序,输入格式为:

morgan 77712173 82738888
lee 45663211 
drew 66678321 12002919 12334556

由于每个人的号码数目并不相同,可以对于每一行进行处理,建立以下程序:

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);
}

3.2 使用 ostringstream

多用于逐步构造输出,最后一起打印的情况。
例如统计以上电话号码数目非法与合法的情况,可以定义两个 ostringstream 对象,分别写入合法和非法的字符,最后通过 oss.str()即可获得字符串内容。


标题:《C++ Primer》第八章:IO类
作者:YaoCheng8667
地址:https://ycisme.xyz/articles/2020/01/09/1578564729424.html