CH8 IO库

8.1

 1 #include <iostream>
 2 #include <string>
 3 #include <sstream>
 4 #include <fstream>
 5 
 6 int main()
 7 {
 8     //cout是一个输出流对象,位于std空间,cin是一个输入流对象
 9     std::cout << "Hello C++ Primer" << std::endl;
10     std::string word;
11     std::cin >> word;
12     std::fstream fs;//fs是一个fstream对象
13     std::stringstream ss;//ss是一个stringstream对象
14     return 0;
15 }

 

IO类型间的关系

C++语言不直接处理输入输出,而是通过一族定义在标准库中的类型来处理IO,这些类型支持从设备读取、向设备写入数据的IO操作,设备可以是文件,控制台窗口等。这些类型定义在三个独立的头文件中:iostream,fstream,sstream.9个标准库类型(宽字符版本算在统一的普通版本中),继承关系如下

 

IO对象不能拷贝或赋值

 1 void print(std::ofstream of)
 2 {
 3     std::cout << "IO test " << std::endl;
 4 }
 5 void print_re(std::ofstream& of)
 6 {
 7     std::cout << "IO referience or pointer" << std::endl;
 8 }
1 std::ofstream print(std::ofstream& of)
2 {
3     std::cout << "IO referience or pointer" << std::endl;
4     std::ofstream of2;
5     return of2;
6 }

 

 9 int main()
10 {
11     //cout是一个输出流对象,位于std空间,cin是一个输入流对象
12     std::cout << "Hello C++ Primer" << std::endl;
13     std::string word;
14     std::cin >> word;
15     std::fstream fs;//fs是一个fstream对象
16     std::stringstream ss;//ss是一个stringstream对象
17     //IO对象不能赋值,下面的赋值操作是错误的
18     std::ofstream out1;
19     std::ofstream out2;
20     out1 = out2;
21     //IO对象也不能拷贝
22     print(cout);//由于传值是拷贝操作,而IO对象不能拷贝,所以这样写是错误的
23     //但IO操作可以通过引用或指针传递和返回流
24     print_re(cout);
25     return 0;
26 }

由于IO对象不能拷贝,所以不能放到对象中,因为保存在容器中的对象都必须可以复制

8.1.2 条件状态

 

IO操作一个与生俱来的问题就是可能发生错误,IO类定义了一些函数和标志,可以帮助我们访问和操纵流的条件状态。badbit:系统级错误,通常情况下,一旦badbit被置位,流就无法使用了。failbit,eofbit,被置位,还可以修正,流还可以继续使用。

 

1 int ival;
2     std::cin >> ival;

 

如上述要求输入一个int型变量,若输入一个char型,则读操作就会失败,cin就会进入错误状态

 1 void check_cin_state(std::istream& is)
 2 {
 3     if (is.bad())
 4         std::cout << "cin is bad" << std::endl;
 5     else
 6         std::cout << "cin is not bad" << std::endl;
 7     if (is.fail())
 8         std::cout << "cin is fail" << std::endl;
 9     else
10         std::cout<<"cin is not fail" << std::endl;
11     if (is.eof())
12         std::cout << "cin is eof" << std::endl;
13     else
14         std::cout << "cin is not eof" << std::endl;
15     if (is.good())
16         std::cout << "cin is good" << std::endl;
17     else
18         std::cout << "cin is not good" << std::endl;
19 }
20 int main()
21 {
22     std::cout << "check the state of cin" << std::endl;
23     check_cin_state(std::cin);
24     std::cout << "please input an integer" << std::endl;
25     int a;
26     std::cin >> a;
27     std::cout << "check the state of cin again" << std::endl;
28     check_cin_state(std::cin);
29     system("pause");
30     return 0;
31 }

要求输入的是int型,输入char型,流状态是fail。

管理流状态

上述一旦流状态is notgood就结束了,可以通过恢复流状态继续使用流

计算输入数字的和的程序为例、

 1 int sum = 0;
 2     int ival;
 3     /*while (std::cin >> ival)
 4     {
 5         sum += ival;
 6         std::cout << "sum is " << sum << std::endl;
 7     }*/
 8     //上述写法一旦输入类型不是int型就结束了,所以可以通过管理流使得流可以继续使用
 9     while (std::cin >> ival, !std::cin.eof())
10     {
11         if (std::cin.bad())
12             throw std::runtime_error("IO stream is not successful");
13         if (std::cin.fail())
14         {
15             std::cout << "IO stream is fail,try again" << std::endl;
16             std::cin.clear();//恢复流状态
17             std::cin.ignore(100, '\n');
18             continue;
19         }
20         sum += ival;
21         std::cout << "sum is  " << sum << std::endl;
22     }
8.2 文件输入输出
头文件fstream定义了三个类型来支持文件IO:ifstream 从 一个给定文件读取数据ofstream向一个给定文件写入数据,发stream可以读写给定文件。
8.2.1文件流的使用
创建文件流对象时,如果提供了文件名,会自动调用open函数打开文件
1 ofstream outfile("test.txt");//创建一个输出流对象outfile,并使用该对象创建一个文件
2     outfile << "Hello C++" << endl;//使用流向文件写入内容
3     outfile.close();//关闭流
4     string txt("t.txt");//文件夹中需要有此文件
5     ifstream infile(txt);//C++11新标准,旧版本需使用C风格字符串infile(txt.c_str())

如果定义了一个了一个空文件(文件流对象没有绑定文件),可以调用open将它与文件关联起来如果调用失败,failbit会被置位,所以进行是否成功检查是一个好习惯

1 ifstream infile;
2     infile.open("t.txt");
3     if (infile)
4     {
5         string str;
6         while(infile >> str)
7         cout << str << endl;
8         infile.close();
9     }

 




 8.3 string流

sstream 头文件定义的三个类型是支持内存IO,即字符串流是内存中的输入输出。

istringstream从string读取数据,ostringstream向string读数据stringstream既可以从string读数据也可以向string写数据。

使用istringstream

当某些工作需要处理某行文本中的单个单词时通常可以使用istringstream

教材中有这样一个例子,家丁一个通讯录文件,列出了一些人和他们的电话,但是有些人会有不止一个电话号码,通常文件的每条记录(每一行)都是以人名开头,后面跟随他们的电话

eg: 小王   130xxxxxxxx  6283xxxx

      小李   158xxxxxxxx

那么首先需要定义一个类PersonInfo来描述输入数据,PersonInfo有一个对象name来表示人名,一个vector<string>来保存电话号码。该程序需要读取兵处理多条PersonInfo记录,所以需要一个vector<PersonInfo>来保存多条记录,使用getline函数读取每一行,使用istringstream读取行中的单个单词。

 1 struct PersonInfo {
 2     std::string name;
 3     std::vector<std::string> phone;
 4     void save_contacts();
 5 };
 6 
 7 
 8 void PersonInfo::save_contacts()
 9 {
10     string line;//保存来自输入的一行记录
11     string word;//保存记录的单个单词
12     vector<PersonInfo> person;//保存输入的所有记录
13 
14     while (getline(std::cin, line))//
15     {
16         PersonInfo info;//创建一个PersonInfo的对象,保存记录
17         istringstream record(line);//创建一个isrting流对象record,并绑定到输入的记录的行
18         record >> info.name;//读取一条记录中的名字给PersonInfo对象的name成员
19         while (record >> word)//读到的记录中的电话号码给PersonInfo对象的phone成员
20             info.phone.push_back(word);
21         person.push_back(info);//将读到的所有记录保存到vector<PersonInfo>中
22     }
23 }

使用ostringstream

 

 1 //使用ostringstream对构造好的输入的记录进行输出
 2     for (const auto entry : person)
 3     {
 4         //创建ostring对象用于输出无效的电话号码和规范为特定格式的后的电话号码
 5         ostringstream badNums;
 6         ostringstream formatted;
 7         //
 8         for (const auto& nums : entry.phone)
 9         {
10             if (!valid(nums))
11                 badNums << " " << nums;
12             else
13                 formatted << " " << format(nums);
14         }
15         if (badNums.str.empty())//如果电话号码有效,输出格式化后的电话号码
16             cout << entry.name << " " << formatted.str();
17         else
18             cerr << "input error :" << endl;
19     }

 

上面的是处理的从cin读取的数据,可以综合文件流和string流实现从文件读取数据

小结

C++使用标准库类来处理面向流的输入输出

iostream 处理控制台IO

fstream 处理命令文件IO

stringstream完成内存string的IO

继承关系如上面的图

每个IO对象都维护一组条件状态,用来指出此对象上是否可进行IO操作,如果遇到了错误,则对象状态变为失效,除非纠正错误才能执行后续操作

 

posted @ 2017-08-15 22:23  Holly_U  阅读(177)  评论(0编辑  收藏  举报