C++相关:C++的IO库

前言

基本的IO库设施

  • istream(输入流类型),提供输入操作。
  • ostream(输出流类型),提供输出操作。
  • cin,一个istream对象,从标准输入读取数据。
  • cout,一个ostream对象,向标准输出写入数据。
  • cerr,一个ostream对象,通常用于输出程序错误消息,写入到标准错误。
  • >>运算符,用来从一个istream对象读取输入数据。
  • <<运算符,用来向一个ostream对象写入输出数据。
  • getline函数,从一个给定的istream对象读取一行数据,存入一个指定的string对象中。

IO类

 

三种最常用的IO头文件

 

  • iostream头文件定义了 控制台读写流的基本类型。
  • fstream定义了读写命名文件的类型。
  • sstream定义了读写内存string对象的类型。

 

IO对象不能拷贝复制

ofstream out1,out2;
out1 = out2;   //报错,不能对流对象复制
ofstream print(ofstream);      //错误,不能初始化ofstream参数
out2 = print(out2);               //错误,不能拷贝流对象

流的条件状态

ostream s;
bool istrue;
istrue = s.eof();   //流到达文件末尾则为true
istrue = s.fail();   //IO失败则为true
istrue = s.bad();  //流崩溃则为true
istrue = s.good();  //流处于有效状态则返回true
s.clear();             //将所有状态复位,流的状态重置为有效状态
s.clear(flags);      //根据指定的flags标志位将流s的对应条件状态位复位
s.setstate(flags); //根据给定的flags标志位,将流s的对应条件状态位置位
s.rdstate();        //返回流的当前状态

管理输出缓冲

缓冲刷新(数据真正地写到输出设备和文件中)的触发机制

  • 程序正常结束,main函数return。
  • 缓冲区满,需要刷新缓冲区。
  • 使用诸如endl(换行)、flush(不附加字符)、ends(附加一个空字符)等操作符显式地刷新缓冲区。
  • 关联输入和输出流。当读写被关联的流时,关联到流的缓冲区会被刷新。如默认情况下,cerr和cin都关联到cout,因此读cin或者写cerr时都会导致cout的缓冲区被刷新。

关联输入输出流

x.tie(&o)的形式,即将流x关联到流o。

cin.tie(&cout);   //展示用,标准库默认将二者绑定
ostream *old_tie = cin.tie(nullptr); //cin不再与其他流关联
cin.tie(&cerr)    //将cin与cerr关联
cin.tie(old_tie) //重建cin和cout的正常关联

文件输入输出流

三种类型:ifstream从指定文件读取数据,ofstream负责写入数据,而fstream可以读写文件。

//1
string filepath;
fstream fs(filepath); //创建一个fstream文件流并打开filepath的文件。

//2.或者
fstream fs(filepath,mode); //按指定模式打开文件
/*模式
in     以读方式打开,ifstream和ftream的默认模式
out    以写的方式打开,ofstream和fstream的默认模式
app    每次写操作前均定位到文件末尾
ate    打开文件立即后立即定位到文件末尾
trunc  截断文件
binary 以二进制的形式进行IO
*/

//3.又或者
fstream fs;
fs.open(filepath);

fs.close();//关闭与fs绑定的文件
fs.is_open();  //返回bool值,指出与fs关联的文件是否成功打开且尚未关闭

自动构造和析构

当一个fstream对象呗销毁时,close函数会被自动调用,如下

for(auto p = argv + 1; p != argv + argc;++p)
{
     ifstream input(*p);  //创建输入流并打开文件
     if(input) //成功打开
     {
          process(input); //处理文件
     }
     else
          cerr << "couldn't open: " + string(*p);
} //每次循环input都会离开作用域而被销毁

注:1.如果ofstream对象要打开的文件不存在,那么它会自动创建一个对应字符串参数名字的文件。

      2.如果文件存在,那么out模式下打开文件会丢弃已有数据,也就是说写入的内容会覆盖原有文件内容,避免这种情况的方法是指定打开的模式为app(append的缩写)。

int main()
{
    string file;
    while(cin >> file)
    {
      ofstream out(file);
      // ofstream out(file,ios::app); 使用这种模式则会将写入内容添加到文件末尾
      if(out)
      {
        string data;
        cin >> data;
        out << data; //会覆盖文件内容
        out.close();
        cout << "Success" << endl;
      }
      else
      {
        cerr << "Open: "<< file <<" failed!" << endl;
        continue;
      }
    }
}

string流

三种类型:istringstream、ostringstream、stringstream,与文件流类似,只不过操作对象从文件变为了string。

stringstream特有的操作:

stringstream strm; //未指定绑定的对象

stringstream strm(s); //拷贝构造

string s = strm.str(); //返回strm流保存的string的拷贝

strm.str(s)   //将字符串s拷贝到strm流中

使用istringstream

1.考虑读取以下数据

 格式:

人名        家庭电话   手机电话

morgan  20141441  2325255224

Jack       23232333   45525222

Lee        7944732   72255252

2.首先确定对象类

struct PersonInfo
{
     string name;
     vector<string> phones;
}
/*
1.C++中struct的默认访问修饰符为public。从语法上来说与class只有访问修饰符的区别
2.一般来说,struct适合构建只含有数据成员的对象,即精简的对象。
3.另外在C#中,struct属于值类型
*/

3.读取数据文件并操作

string line,word;
vector<PersonInfo> people;
//逐行从输入中读取数据,直至cin遇到文件末尾或者其他错误
while(geline(cin,line))
{
    PersonInfo info;
    istringstream record(line); //将记录绑定到刚读入的行
    record >> info.name; //读入名字,注意string流以空格为默认分界符
    while(record >> word)
          info.phones.push_back(word); //读取电话
    people.push_back(info);
}

使用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);    //写入formatted等待输出

if(badNums.str().empty()) os << entry.name << " " << formatted.str() << endl;//符合格式,成功输出 else cerr << "input error:" << entry,name << "invalid number(s)" << badNums.str() << endl; } }

 总结

  • iostream负责控制台IO
  • fstream负责文件IO
  • stringstream负责内存中string的IO

另外,类fstream和stringstream都是继承自iostream,所以输入类都继承自istream,输出类都继承自ostream。因此,在istream对象上执行的操作同样可以应用于ifstream或者istringstream对象;ostream同理。

posted @ 2017-10-23 12:20  0kk470  阅读(420)  评论(0编辑  收藏  举报