【C++学习】标准库:IO类(总结C++primer第八章)

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

  • 之前已经使用的IO库设施:istream类型、ostream类型、cin、cout、cerr、>>运算符、<<运算符、getline函数;

    头文件类型
    iostreamistream/wistream 从流读数据
    ostream/wostream 向流写数据
    iostream/wiostream 读写流
    fstreamifstream/wifstream 从文件读数据
    ofstream/wofstream 向文件写数据
    fstream/wfstream 读写文件
    sstreamistringstream/wistringstream 从string读数据
    ostringstream/wostringstream 向string写数据
    stringstream/wstringstream 读写string

    宽字符版本的数据和函数以一个w开始,如wcin对应cin的宽字符版对象。

IO类

  • IO对象不能拷贝或赋值,也不能将形参或返回类型设置为流类型:

    ofstream out1, out2;
    out1 = out2;    // 错误,流对象不能赋值
    ofstream print(out1);    // 错误,函数不能以ofstream为形参,不能以ostream为返回类型
    out2 = print(out1);    // 错误,不能拷贝流对象
    
  • 条件状态

    IO库条件状态
    strm::badbit流已崩溃
    strm::failbit一个IO操作失败
    strm::eofbit流到达了文件结束
    strm::goodbit指出流未处于错误状态,此值保证为0
    s.eof()若流s的eofbit置位,则返回true
    s.fail()若流s的failbit或者badbit置位,则返回true
    s.bad()若流s的badbit置位,则返回true
    s.good()若流s的goodbit置位,则返回true
    s.clear()将流s中所有条件状态复位,将流的状态设置为有效,返回void
    • 代码通常应该在使用一个流之前检查它是否处于良好状态

      while (cin >> word);
      
  • 管理输出缓冲

    • 有了缓冲机制,操作系统就可以将程序的多个输出操作组合成单一的系统级写操作;

    • 刷新输出缓冲区:

      cout << "hi!" << endl;    // 输出内容和一个换行,然后刷新缓冲区
      cout << "hi!" << flush;    // 输出内容,然后刷新缓冲区
      cout << "hi!" << ends << 1;    // 输出内容和一个空字符,然后刷新缓冲区。
      
      • 如果程序异常终止,输出缓冲区不会被刷新;
  • 关联输入和输出流

    • 当一个输入流被关联到一个输出流时,任何试图从输入流读取数据的操作都会先刷新关联的输出流。标椎库将cout和cin关联在一起:

      cin >> ival;    // cout被刷新
      
    • 交互式系统应该关联输入输出流,这样能保证所有输出,都会在读操作之前被打印出来,否则可能出现输入后的回应是输入前的输出的情况;

    • istream和ostream类型的tie成员都只能接收ostream *类型参数:

          cin.tie(&cout);
          cin.tie(&cin);    // 错误,无此函数
          
          cout.tie(&cerr);
          cout.tie(&cin);    // 错误,无此函数
      
    • 解除关联:

      cin.tie(nullptr);   
      

文件输入输出

  • 头文件fstream定义了三个类型来支持文件IO:ifstream;ofstream;fstream

  • fstream头文件中继承自iostream的行为:

    • 用IO运算符(<<和>>)来读写文件;

    • 用getline从一个ifstream读取数据:

    • getline(cin,line);
      
  • fstream中增加新的成员来管理与流关联的文件:

    fstream特有操作含义
    fstream fstrm创立一个未绑定的文件流
    fstream fstrm(s)创立一个fstream,并打开名为s的文件
    fstream fstrm(s)与前一个函数类似,但按指定mode打开文件
    fstrm.open(s)打开名为s的文件,并将文件与fstrm绑定
    fstrm.close()关闭与fstrm绑定的文件
    fstrm.close()返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭
  • 使用文件流对象

    • 用fstream代替iostream&;

    • 成员函数open和close:如果定义了一个空文件流对象,可以随后调用open来将它与文件关联起来,首先必须关闭已经关联的文件

      ifstream in(ifile);
      ofstream out;
      out.open(ifile+".copy")
      

      因为调用open可能失败,失败后failbit会被置位,所以最好检测open是否成功:

      if (out)
      
  • 自动构造和析构:当一个fstream对象被销毁时,close会自动被调用。

  • 文件模式:

    • in:以读方式打开,只可以对ifstream或fsteam对象设置in模式(默认与ifstream关联的文件以in模式打开);
    • out:以写方式打开只可以对ofstream或fsteam对象设置out模式(默认与ofstream关联的文件以out模式打开);
      • 以out模式打开文件会丢失已有数据;
      • 保留被ofstream打开的文件中已有数据的唯一方法是显示制定app或in模式。

string流

  • string头文件定义了三个类型来支持内存IO:

    • istringstream从string读取数据;

    • ostringstream向string写入数据;

    • stringstream既可读数据也可写数据。

      stringstream特有操作含义
      sstream strm创立一个未绑定的stringstream对象
      sstream strm(s)创立一个sstream对象,保存string s的一个拷贝
      strm.str()返回strm所保存的string的拷贝
      strm.str(s)将string s 拷贝到strm中,返回void
  • 使用istringsteam

    • 当我们的某些工作是对整行文本进行处理,而其他工作是处理行内的单个单词时,通常可以使用istringstream:

      struct PersonInfo {
          string name;
          vector<string> phones;
      };
      
      string line, word;
      vector<PersonInfo> people;
      while (getline(cin, line)) {//从标准输入读取整条记录
          PersonInfo info;
          istringstream record(line);    // 将记录绑定到刚读入的行,record不变
          record >> info.name; //从一个string读取一个单词作为名字
          while (record >> word) {//从一个string读取电话号码
              info.phones.push_back(word);
          }
          people.push_back(info);
      }
      
  • 使用ostringstream

    • 当我们逐步构造输出,希望最后一起打印时,可以使用ostringstream对象:

      for (const auto &entry : people) {    // 遍历每一条信息
          ostringstream formatted, badNums;
          
          for (const auto &nums : entry.phones) {    // 遍历每一条信息中的电话号码
              if (!valid(nums)) {    // 如电话号不合法
                  badNums << " " << nums;    // 以字符串形式存入badNums
              } else {
                  formatted << " " << format(nums);    // 如合法,将字符串以format函数返回的格式存入formatted
              }
          }
          
          if (badNums.str().empty()) {    // 如没有不合法的电话号
              cout << entry.name << " " << formatted.str() << endl;
          } else {
              cerr << "input error: " << entry.name << "invalid number(s) " << badNums.str() << endl;
          }
      }    
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值