C++常见问题总结_IO库

IO库

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

IO类

#include<iostream>
istream; wistream;
ostream; wostream;
iostream; wiostream;
#include<fstream>
ifstream; wifstream;
ofstream; wostream;
fstream; wfstream;
#include<sstream>
istringstream; wistringstream;
ostringstream; wostringstream;
stringstream; wstringstream;

iostream定义了用于读写流的基本类型,fstream定义了读写命名文件的类型,sstream定义了读写内存string对象的类型。为了支持使用宽字符的语言,标准库定义了一组类型和对象来操作wchar_t类型的数据。
类型ifstream和istringstream都继承自istream;ofstream和ostringstream继承自ostream。

  • IO对象无拷贝或赋值
ofstream out1,out2;
out1=out2;        //错误,不能对流对象赋值
ofstream print(ofstream); // 错误不能初始化ofstream参数
out2=print(out2); //错误

由于不能拷贝IO对象(无拷贝构造函数),因此我们不能将形参或返回类型设置为流类型,进行IO操作的函数通常以引用方式传递和返回流。读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。

  • 条件状态
    IO类定义了一些函数和标志,可以帮助我们访问和操作流的条件状态。
//条件状态 strm表示上述一种IO类型

strm::iostate;//一种机器相关的类型,提供了表达条件状态的完整功能

strm::badbit; //流已经崩溃 ,系统级错误不可恢复的 

strm::failbit; //指出IO操作失败 可以恢复的,流还可以继续使用。(到达文件结束是会被置位)

strm::eofbit;//到达了文件结束 到达文件结束是会被置位

strm::goodbit;//未出现错误状态时此值为0;

s.eofbit();  //eofbit置位 返回true
s.fail();    //failbit或badbit置位 返回true
s.good();    //处于有效状态   返回true
s.bad();     //badbit置位 返回true
s.clear();   //流的所有条件状态复位,流的状态设置为有效 返回void
s.clear(flag); //给定条件状态位复位 flag的类型为strm::iostate 返回void
s.setstate(flag);//根据给定的flag标志位,将流s中对应的条件状态位置位 返回void
s.rdstate();     //返回当前状态 类型strm::iostate

badbit表示系统级错误,如不可恢复的读写错误。通常情况下,一旦badbit被置位,流就无法再使用了。在发生可恢复错误后,failbit被置位,如读取数值却读到一个字符等。这种问题可以修正流还可以继续使用。如果到达文件结束位置,eofbit和failbit都会被置位。goodbit的值为0,表示流未发生错误。如果badbit、failbit和eofbit任一个被置位,则检查流的条件会失败。(将流当做条件的代码等价于!fail()。)

//管理条件状态
while(cin>>word);//流保持有效状态时为真

    auto old_state=cin.rdstate();   //记住流cin的当前状态
    cin.clear();//复位
    pross(cin);
    cin.setstate(old_state); //回复之前的状态

c.clear(cin,rdstate&~cin.failbit&~cin.badbit);//只复位failbit和badbit

iostate类型是一种与机器无关的类型,它提供了表达流状态的完整功能。这个类型应作为一个位集合来使用。IO库定义了四个iostate类型的常量值,表示特定的位模式。

  • 管理输出缓冲
    每个输出流管理一个缓冲区,用来保存程序的读写的数据,可以将程序的多个输出操作组合成单一的系统级写操作,由于设备的写操作很耗时。
//刷新输出缓冲区
cout<<"hi"<<endl;//输出hi和换行,然后刷新缓冲区
cout<<"hi"<<flush;//输出hi然后刷新缓冲区
cout<<"hi"<<ends;//输出一个hi和一个空字符,然后刷新(向缓冲区插入一个空字符,然后刷新缓冲区)

cout<<unitbuf;//所有输出操作都会立即刷新 每一次写操作之后都进行一次flush操作
count<<nounitbuf;//回到正常的系统管理的缓冲区刷新机制

note:程序正常执行,作为return的一部分 输出缓冲区被刷新,如果程序崩溃输出缓冲区不会刷新。

  • 关联输入和输出流
    一个输出流可能被关联到另一个流上。在这种情况下,当读写被关联的流时,关联到的流的缓冲区会被刷新。cin和cerr都被关联到cout。因此,读cin或写cerr都会导致cout的缓冲区被刷新。
//tie成员函数 两个重载版本
//c.tie();//如果当前流关联到一个输出流,就会返回指向该流的指针,没有为void
// x.tie(&o);//x关联到o 返回指向前流之前关联的输出流的指针, 没有为void

    cin.tie(&cout);
    ostream *old_tie=cin.tie(nullptr); //cin不在与其他流关联 old_tie指向当前关联到cin的流
    cin.tie(&cerr);// 读取cin会刷新
    cin.tie(old_tie);//将cin重新关联到cout

每个流同时最多关联到一个流,但多个流可以同时关联到同一个ostream。

文件输入输出

#include<fstream>
ifstream;
ofstream;
fstream;

除了继承自iostream类型的行为之外,fstream中定义的类型还增加了一些新的成员来管理与流关联的文件。
我们可以对文件类型的流调用如下操作,但是不能对其他IO类型调用这些操作。

//fstream 是上述三种类型中的一种
fstream fstrm;//创建一个未绑定的文件流
fstream fstrm(s); //创建一个fstream对象,并打开文件s(string或者是c风格字符串指针),这些构造函数是explicit的。
fstream fstrm(s,mode);//按照指定模式打开

fstrm.open(s);//打开s文件,并与fstrm绑定。
fstrm.close();//关闭绑定的文件 并返回void
fstrm.is_open();//返回bool值,指出关联的文件是否成功打开且尚未关闭的
  • 使用文件流对象
ifstream in(ifile); //构造一个ifstream 并打开指定文件
ofstream out; //输出文件流未关联到任何文件
  • 成员函数open和close
    我们定义了一个空文件流对象,可以随后调用open来将它与文件关联
ifstream in(ifile); //构造一个ifstream 并打开指定文件
ofstream out; //输出文件流未关联到任何文件
out.open(ifile+".copy");//打开指定文件
//通常调用open失败,failbit会被置位,因此通常需要检测
//对一个已经打开的文件流调用open会失败,若想在使用该流,首先要关闭已经关联的文件。
    if(out)        
        process(out);
    in.close();
    in.ope(infile.2);
  • 自动构造和析构
for(auto p=agrv+1;p!=argv+argc;++p){
    ifstream input(*p);
    if(input){
        process(input);
    }else
        cerr<<"couldn't open: "+string(*p);
}

当一个fstream对象离开其作用域时,与之关联的文件会自动关闭。在下一步循环中,input会再次创建。
当一个fstream对象被销毁时,close会自动被调用。

扫描二维码关注公众号,回复: 1475443 查看本文章
  • 文件模式
in  读方式打开
out 写方式打开
app 每次写操作都定位到文件末尾
ate 打开文件后立即定位到文件末尾
trunc 截断文件
binary 以二进制方式打开

1、只可以对ofstream或fstream对象设定out模式
2、只可以对ifstream或fstream对象设定in模式
3、只有当out也被设定时才可以设定trunc模式
4、只有trunc没被设定,就可以设定app模式。在app模式下,即使没有显示指定out模式,文件总是以输出方式被打开
5、默认情况下,即使我们没有指定trunc,以out模式打开的文件也会被截断。为了保留以out模式打开文件的内容,我们必须同时指定app模式;或者同时指定in模式,即打开文件的同时进行读写操作。

//以out模式打开文件会丢弃已有的数据
ofstream out("file1");//隐含以输出模式打开并截断
ofstream out("file1",ofstream::out);//隐含截断
ofstream out("file1",ofstream::out|ofstream::trunc);

ofstream app("file1",ofstream::app);//追加模式 隐函输出
ofstream app("file1",ofstream::app|ofstream::out);

//每次调用open都会确定文件模式
ofstream out;// 未指定文件打开模式
out.open("dasd"); //模式隐含设置为输出和截断
out.close();
out.open("qwe",ofstream::app);//模式为输出和追加
out.close;

string流

#include<sstream>
istringstream;
ostringstream;
stirngstream;

除了继承得来的操作,sstream中定义的类型还增加了一些成员来管理与流相关联的string。

//stringstream特有操作:(sstream为头文件中的一种类型)
sstream strm;//未绑定的对象
sstream strm(s);//strm是一个sstream对象,保存s拷贝的 sstream对象。此构造函数是explicit的

strm.str(); //返回strm所保存的string的拷贝
strm.str(s);//将s拷贝到strm中,返回void。
//使用istringstream
/*输入格式: liumou 165164 646131
            dreqwe 41568 46746
            ....
*/
struct personinfo{
    string name;
    vector<string> phones;
};

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(info);
    people.push_back(info);
}

//使用ostringstream
/*当我们需要逐步构造输出,希望最后一起打印时,ostringstream很有用。
  对于上面实例我们想逐个验证电话号码,并改变格式,号码有效,输出一个新的文件。无效的号码,我们不会
  将其输出,而是打印错误信息。
  valid(完成电话号码的验证)
  format(改变格式)
*/
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(badnum.str().empty()) //没有错误的子
        os<<entry.name<<" "<<formatted.str()<<endl;
    else
        cerr<<"input error: "<<entry.name
        <<" invalid numbers "<<badnums.str()<<endl;
}

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

  • iostream处理控制台IO
  • fstream处理命名文件IO
  • stringstream完成内存string的IO
    类fstream和stringstream都是继承自iostream的,输入类继承自istream,输出类继承自ostream。
    每个IO对象都维护一组条件状态,用来指出此对象上是否可以进行IO操作。如果遇到了错误,则对象的状态变为失效,则后续的操作不能执行,直至错误被纠正。标准库定义了一组函数,用来设置和检测这些状态。

猜你喜欢

转载自blog.csdn.net/xc13212777631/article/details/80431893