c++标准库:8-io库

218 阅读3分钟

iostream

iostream即标准输入输出流,用于操纵char数据,默认关联到用户的控制台窗口。每一种流对象都对应包含一个操纵宽字符wchar_t类型数据的版本:

头文件类型作用
<iostream>istream, wistream输入流:从流读取数据
<iostream>ostream, wostream输出流:向流写入数据
<iostream>iostream, wiostream输入输出流:读写流
  • io对象不能拷贝、不能赋值,因此

    • io操作的函数通常以引用的方式传递和返回流

    • io对象读写会改变其状态,所以传递和返回的引用也不能是const

      #include <iostream>
      #include <ostream>
      // 以引用的方式传递和返回流
      std::ostream &print(std::ostream &os) {
        os << "print some info" << std::endl;
        return os;
      }
      
      int main(int argc, const char **argv) {
        std::ostream &os = print(std::cout);
        os << "main end" << std::endl;
        return 0;
      }
      
  • ostream缓冲刷新时机:

    • main函数正常结束时,缓冲刷新;

    • 缓冲区满时,缓冲刷新;

    • 使用endl、flush、ends操纵符显式刷新;

      std::cout << "endl输出内容和一个换行符,然后刷新缓冲" << std::endl;
      std::cout << "ends输出内容和一个空白符,然后刷新缓冲" << std::ends;
      std::cout << "flush输出内容不附加任何字符,然后刷新缓冲" << std::flush;
      
    • 使用unitbuf操纵符让流在接下来的每次写操作之后都进行一次flush操作;nounitbuf操纵符重置流为默认刷新机制;

      std::cout << unitbuf; // 每次写操作之后都刷新缓冲
      //...
      std::cout << nounitbuf; // 重置为默认刷新机制
      
      std::cerr << "xxx"; // cerr是默认设置了unitbuf的,写到cerr的内容都是立即刷新的
      
    • 读写被关联的流时,关联的流缓冲区会被刷新;

      // cin和cerr都默认关联到cout,当读cin、写cerr时会导致cout缓冲区被刷新
      // 关联伪代码形如:
      cin.tie(&cout);
      cerr.tie(&cout);
      
      // 关联的cout缓冲区被刷新
      cin >> val;
      cerr << "err";
      

fstream

fstream为文件流,继承自iostream,具有iostream类型的所有行为,如可以使用<< >>来读写文件。文件流对象包含如下类型:

头文件类型作用
<fstream>ifstream, wifstream文件输入流:从文件流读取数据
<fstream>ofstream, wofstream文件输出流:向文件流写入数据
<fstream>fstream, wfstream文件输入输出流:读写文件流

文件模式

每个文件流都有一个关联的文件模式:

模式含义限制
in以读方式打开只能对ifstream和fstream对象设定in模式
out以写方式打开只能对ofstream和fstream对象设定out模式
app以附加方式打开,每次写前均定位到文件末尾app模式下,默认也是out 的
ate打开文件时立即定位到文件末尾可用于任何文件流对象,可与其他任何模式组合
trunc截断文件只有out被设定时才能设定trunc
binary以二进制的方式进行io可用于任何文件流对象,可与其他任何模式组合
  • ifstream关联的文件默认为in模式;
  • ofstream关联的文件默认为out | trunc模式;
  • fstream关联的文件默认为in | out模式;
ofstream out("out_file"); // 等价于
ofstream out("out_file", ofstream::out); // 等价于
ofstream out("out_file", ofstream::out|ofstream::trunc);

ofstream app("app_file", ofstream::app); // 等价于
ofstream app("app_file", ofstream::out|oftream::app)

特有操作

通过一个文件读写的示例,来说明文件流的特有操作: open()、is_open()、close()

#include <fstream>
#include <iostream>
#include <string>

int main(int argc, const char **argv) {
  std::string in_file = "io-fstream.cc";
  std::string out_file = in_file + ".copy";

  std::ifstream in_fs;
  in_fs.open(in_file);
  // 上述两行也等价于下面两种写法:
  // std::ifstream in_fs(in_file);
  // std::ifstream in_fs(in_file, std::ifstream::in);

  std::ofstream out_fs;
  out_fs.open(out_file);
  // 上述两行也等价于下面两种写法:
  // std::ofstream out_fs(out_file);
  // std::ofstream out_fs(out_file, std::ofstream::out | std::ofstream::trunc);

  if (in_fs.is_open()) {
    std::string line;
    while (std::getline(in_fs, line)) {
      out_fs << line << std::endl;
    }
  }

  // 关闭文件流对象
  // 也可以不写,当一个文件流对象被销毁(离开作用域)时,close会自动调用
  in_fs.close();
  out_fs.close();

  return 0;
}

sstream

sstream为字符串流,同样继承自iostream,具有iostream类型的所有行为。字符串流包含如下类型:

头文件类型作用
<sstream>istringstream, wistringstream字符串输入流:从字符串流读取数据
<sstream>ostringstream, wostringstream字符串输出流:向字符串流写入数据
<sstream>stringstream, wsstringstream字符串输入输出流:读写字符串流

特有操作

通过一个字符串流读写的示例,来说明字符串流的特有操作: str()

#include <iostream>
#include <sstream>
#include <string>
#include <vector>

std::string text = R"(morgan 32397293833 48727373221
drew 74783488881
lee 73283882111 382893238 3232323212)";

struct Person {
  std::string name;
  std::vector<std::string> phones;
};

int main(int argc, const char **argv) {
  // 将string拷贝到字符串输入流中
  std::istringstream istr(text);
  // 上面一行等价于:
  // std::istringstream istr;
  // istr.str(text);

  std::string line, word;
  std::vector<Person> persons;

  // 将text结构化为vector<Person>类型
  while (std::getline(istr, line)) {
    std::istringstream row(line);
    Person person;
    row >> person.name;
    while (row >> word) {
      person.phones.push_back(word);
    }
    persons.push_back(person);
  }
  // 输出vector<Person>的信息
  for (const auto person : persons) {
    // 用两个字符串输出流来写入正确和错误的电话号码
    std::ostringstream ok_phones, bad_phones;
    for (const auto phone : person.phones) {
      if (phone.size() != 11) {
        bad_phones << " " << phone;
      } else {
        ok_phones << " " << phone;
      }
    }
    if (bad_phones.str().empty()) {
      std::cout << person.name << " " << ok_phones.str() << " phone ok."
                << std::endl;
    } else {
      std::cerr << person.name << " "
                << "has bad phones:" << bad_phones.str() << std::endl;
    }
  }

  return 0;
};

参考书籍:《C++ Primer》第5版