C++ Primer 5th学习笔记7 IO库

IO库

1 IO类

常用的IO库类型和头文件如下表:

头文件 类型
iostream istreamwistream从流读取数据
ostreamwostream 向流写入数据
iostreamwiostream 读写流
fstream ifstreamwifstream 从文件读取数据
ostreamwofstream 向文件写入数据
fstreamwfstream 读写文件
sstream istringstreamwistringstream 从string读取数据
ostringstreamwostringstream 向string写入数据
stringstreamwstringstream 读写string

w开头的表示宽字符类型

1.1 条件状态

IO库条件状态
名称 描述
strm::iostate strm是一种IO类型,在上表中已列出
strm::badbit 用来指出流已经崩溃
strm::failbit 用来指出一个IO操作失败了
strm::eofbit 用来指出流到达了文件结束
strm::goodbit 用来指出流未处于错误状态
s.eof() 若流s的eofbit置位,则返回true
s.fail() 若流s的failbitbadbit置位,则返回true
s.bad() 若流s的badbit置位,则返回true
s.good() 若流s处于有效状态,则返回true
s.clear() 将流s中所有条件状态复位,将流的状态设置为有效。返回void
s.clear(flags) 根据给定的flag标志位,将流s中对应条件状态位复位。flag类型为strm::iostate
s.setstate(flags) 根据给定的flag标志位,将流s中对应条件状态位置位。flag类型为strm::iostate
s.rdstate() 返回流s的当前条件状态,返回类型为strm::iostate

1.2 管理输出缓冲

  每一个输出流都管理一个缓冲区,用来保存程序读写的数据。其中导致缓冲区刷新的原因有如下几种:

  • 程序正常结束
  • 缓冲区满时,需要刷新缓冲区,后面新来的数据才能继续写入缓冲区
  • 使用操作符如endl来显示刷新缓冲
  • 在每个输出操作之后,可以用操作符unitbuf设置流的内部状态,来清空缓冲区
  • 一个输出流可能被关联到另一个流,当读写被关联的流时,关联到的流的缓冲区会被刷新

刷新输出缓冲区操作符:flush和ends,其中flush刷新缓冲区,但不输出任何额外的字符;ends向缓冲区插入一个空字符,然后刷新缓冲区。

2 文件输入输出

  头文件fstream定义了三个类型来支持文件IO:ifstream从一个给定文件读取数据,ofstream向一个给定文件写入数据,fstream可以读写给定文件

`fstream`特有的操作
名称 描述
fstream fstrm; 创建一个未绑定的文件流
fstream fstrm(s); 创建一个fstream,并打开名为s的文件,s可以是string类型,或指向C风格字符串的指针
fstream fstrm(s, mode); 创建一个fstream,并打开名为s的文件,按指定mode打开文件
fstrm.open(); 打开名为s的文件,并将文件与fstrm绑定
fstrm.close(); 关闭与fstrm绑定的文件。返回void
fstrm.is_open(); 返回一个bool值,表示与fstrm关联的文件是否打开成功并且尚未关闭

示例:

ifstream in(ifile);       //创建一个ifstream并打开给定文件
ofstream out;        //输出文件流
out.open(ifile + ".txt");        //打开指定文件

2.1 文件模式

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

指定文件模式有如下限制:

  • 只可以对ofstreamfstream对象设定out模式
  • 只可以对ifstreamfstream对象设定in模式
  • 只有当out也被设定时,才可设定trunc模式
  • ate和binary模式可用于任何类型的文件流对象,且可以与其他任何文件模式组合使用
  • 只要trunc没有被设定。就可以设定app模式。在app模式下即使没有显式指定out模式,文件也总是以输出方式被打开。
  • 即使没有指定trunc,以out模式打开的文件也会被截断,因此为保留此时的内容,必须同时指定app模式,这样数据将追加写到文件末尾

Tips:当打开一个ofstream时文件的内容会被丢弃,因此此时必须显式指定app或in模式
示例如下:

//文件内容会被截断
ofstream app("file2");
ofstream app("file2", ofstream::out);
//文件内容保留
ofstream app("file2", ofstream::app);
ofstream app("file2", ofstream::out | ofstream::app);

3 string流

string特有的操作
名称 描述
sstream strm; strm是一个未绑定的stringstream对象。sstream是头文件sstream中定义的一个类型
sstream strm(s); strm是一个sstream对象,保存string s的一个拷贝
strm.str() 返回strm所保存的string的拷贝
strm.str(s) string s拷贝到strm中,返回void

3.1 使用istringstream

示例如下:
现有一个这样的文件,其输入格式如下:

morgan 2015552368 8625550123
drew 9735550130
lee 6095550132 2015550175 8005550000

首先定义一个简单的类来描述输入数据:

struct PersonInfo{
    string name;
    vector<string> phones;
}

读取信息的实例函数如下:

扫描二维码关注公众号,回复: 5781797 查看本文章
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);       //将此记录追加到people末尾
}

这里的istringstreamgetline读取的文本进行绑定,然后在istringstream上使用输入运算符来读取当前记录中的每个元素,即元素之间以空格为区分。

3.2 使用ostringstream

对于上例,现将每个人的电话打印出来,但是不希望输出无效电话号码的人,因此需要进行验证。此时可以先将要输出的内容“写入”到一个内存ostringstream中,其代码如下:

for(const auto &entry : people)          //对people中的每一项
{
    ostringstream formatted,badNums;     //每个循环步创建的对象
    for(const auto &num : entry.phones)  //对每个数
    {
        if(!valid(nums))
        {
            badNums << " " << nums;      //将数的字符串形式存入badNums
        }
        else
        formatted << " " << format(num); //将格式化的字符串“写入”formatted
    }
    if(bad.Nums.str().empty())           //没有错误的数
    //打印名字和格式化的数
    os << entry.name << " " << formatted.str() << endl;
    else//打印名字和错误的数
    ceer << "input error: " << entry.name 
         << " invalid number(s)" << badNums.str() << endl;
}

猜你喜欢

转载自blog.csdn.net/qq_18150255/article/details/88785842