C++的IO库简介

mn6e 9年前

和文件有关系的输入输出类主要在fstream.h这个头文件中被定义,在这个头文件中主要被定义了三个类,由这三个类控制对文件的各种输入输出操 作,他们分别是ifstream、ofstream、fstream,其中fstream类是由iostream类派生而来,他们之间的继承关系见下图所 示。

由于文件设备并不像显示器屏幕与键盘那样是标准默认设备,所以它在fstream.h头文件中是没有像cout那样预先定义的全局对象,所以我们必须自己定义一个该类的对象,我们要以文件作为设备向文件输出信息(也就是向文件写数据),那么就应该使用ofstream类。

ofstream类的默认构造函数原形为:

ofstream::ofstream(const char *filename,int mode = ios::out,int openprot = filebuf::openprot);

filename:  要打开的文件名
mode:    要打开文件的方式
prot:    打开文件的属性

其中mode和openprot这两个参数的可选项表见下表:

mode属性表
ios::app:   以追加的方式打开文件
ios::ate:   文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary:  以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
ios::in:    文件以输入方式打开
ios::out:   文件以输出方式打开
ios::trunc:  如果文件存在,把文件长度设为0

可以用“或”把以上属性连接起来,如ios::out|ios::binary。

openprot属性表:

0:普通文件,打开访问
1:只读文件
2:隐含文件
4:系统文件

可以用“或”或者“+”把以上属性连接起来 ,如3或1|2就是以只读和隐含属性打开文件。

示例代码如下

#include <fstream>     using namespace std;     int main()     {     ofstream myfile("c://1.txt",ios::out|ios::trunc,0);     myfile<<"U love C++"<<endl;    myfile.close();     system("pause");    return 0;     }


文件使用完后可以使用close成员函数关闭文件。

ofstream::app为追加模式,在使用追加模式的时候同时进行文件状态的判断是一个比较好的习惯。 如下面的代码:

#include <iostream>    #include <fstream>    using namespace std;    int main()    {        ofstream myfile("e://1.txt",ofstream::app);        if(myfile.fail())            {                cout << "文件创建失败!"<<endl;                exit(-1);            }        myfile << " Cobing" <<endl;        myfile.close();        system("pause");        return 0;    }

在定义ifstream和ofstream类对象的时候,我们也可以不指定文件。以后可以通过成员函数open()显式的把一个文件连接到一个类对象上。如下例:

  1. #include <iostream>    #include <fstream>    using namespace std;    int main()    {        ofstream myfile;        myfile.open("e://1.txt",ofstream::app);        if(myfile.fail())            {                cout << "文件创建失败!"<<endl;                exit(1);            }        myfile << "Cobing" <<endl;        myfile.close();        system("pause");        return 0;    }

下面我们来看一下是如何利用ifstream类对象,将文件中的数据读取出来,然后再输出到标准设备中的例子。

#include <iostream>    #include <fstream>    #include <string>    using namespace std;    int main()    {        ifstream myfile;        myfile.open("e://1.txt",ifstream::in);        if(myfile.fail())            {                cout << "文件打开失败!"<<endl;                exit(1);            }        char ch;        string content;        while(myfile.get(ch))        {            content+=ch;        }        myfile.close();        cout << content <<endl;        system("pause");        return 0;    }

我们利用成员函数get(),逐一的读取文件中的有效字符,get()成员函数会在文件读到默尾 的时候返回假值,所以我们可以利用它的这个特性作为while循环的终止条件,我们同时也在上例中引入了C++风格的字符串类型string,在循环读取 的时候逐一保存到content中。

 

我们在简单介绍过ofstream类和ifstream类后,我们再来看一下fstream类,fstream类是由iostream派生而来,fstream类对象可以同对文件进行读写操作。

  1. #include <iostream>    #include <fstream>    using namespace std;    int main()    {        fstream myfile;        myfile.open("e://1.txt",fstream::out|fstream::app);        if(myfile.fail())            {                cout << "open failed!"<<endl;                exit(1);            }        myfile << "cobing love C++" << endl;        myfile.close();        myfile.open("e://1.txt",fstream::in);        if(myfile.fail())        {            cout << "open file failed!"<<endl;            exit(1);        }           char ch;        while(myfile.get(ch))        {            cout << ch;        }        myfile.close();        system("pause");        return 0;    }

由于fstream类可以对文件同时进行读写操作,所以对它的对象进行初始话的时候一定要显式的指定mode和openprot参数。

接下来我们来学习一下串流类的基础知识,什么叫串流类
简单的理解就是能够控制字符串类型对象进行输入输出的类,C++不光可以支持C++风格的字符串流控制,还可以支持C风格的字符串流控制。

我们先看看看C++是如何对C风格的字符串流进行控制的,C中的字符串其实也就是字符数组,字符数组内的数据在内存中 的位置的排列是连续的,我们通常用char str[size]或者char *str的方式声明创建C风格字符数组,为了能让字符数组作为设备并提供输入输出操作,C++引入了ostrstream、istrstream、 strstream这三个类,要使用他们创建对象就必须包含strstream.h头文件。
istrstream类用于执行C风格的串流的输入操作,也就是以字符串数组作为输入设备。
ostrstream类用于执行C风格的串流的输出操作,也就是一字符串数组作为输出设备。
strstream类同时可以支持C风格的串流的输入输出操作。

istrstream类是从istream(输入流类)和strstreambase(字符串流基类)派生而来,ostrstream是从 ostream(输出流类)和strstreambase(字符串流基类)派生而来,strstream则是从iostream(输入输出流类)和和 strstreambase(字符串流基类)派生而来。

 

串流同样不是标准设备,不会有预先定义好的全局对象,所以不能直接操作,需要通过构造函数创建对象。

类istrstream的构造函数原形如下:
istrstream::istrstream(const char *str,int size);
参数1表示字符串数组,而参数2表示数组大小,当size为0时,表示istrstream类对象直接连接到由str所指向的内存空间并以/0结尾的字符串。

#include <iostream>    #include <strstream>    using namespace std;    int main()    {        char *name = "key love c++";        int arraysize = strlen(name) + 1;        istrstream istr(name,arraysize);        char temp='.';        istr >> temp;        system("pause");        return 0;    }

类ostrstream用于执行C风格的串流的输出,它的构造函数如下所示:
ostrstream::ostrstream(char *_Ptr,int streamsize,int Mode = ios::out);
第一个参数是字符数组,第二个是说明数组的大小,第三个参数是指打开方式。

接下来我们继续看一下C++风格的串流控制,C++引入了ostringstream、istringstream、stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件。
istringstream类用于执行C++风格的串流的输入操作。
ostringstream类用于执行C++风格的串流的输出操作。
stringstream类同时可以支持C++风格的串流的输入输出操作。

 

istringstream是由一个string对象构造而来,istringstream类从一个string对象读取字符。
istringstream的构造函数原形如下:
istringstream::istringstream(string str);

  1. #include <iostream>    #include <sstream>    using namespace std;    int main()    {        istringstream is;        is.str("k e y 1");        cout << is.str() <<endl;        system("pause");        return 0;    }

ostringstream的构造函数原形如下:
ostringstream::ostringstream(string str);
 

#include <iostream>    #include <sstream>    #include <string>    using namespace std;    int main()    {        ostringstream os;        os.put('a');        os.put('b');        os << "ccde";        string str = os.str();        cout << str << endl;        system("pause");        return 0;    }

 

上例在控制台输出"abccde";

我们通过put()或者左移操作符可以不断向ostr插入单个字符或者是字符串,通过str() 函数返回增长过后的完整字符串数据,但值得注意的一点是,当构造的时候对象内已经存在字符串数据的时候,那么增长操作的时候不会从结尾开始增加,而是修改 原有数据,超出的部分增长。

stringstream的构造函数原形如下:
stringstream::stringstream(string str);

stringstream类的对象我们还常用它进行string与各种内置类型数据之间的转换。

  1. #include <iostream>    #include <sstream>    #include <string>    using namespace std;    int main()    {        stringstream format_message;        int val1=512, val2=1024;        string init_str="/nwell done";        format_message << "val1:" << val1 << "/n"                       << "val2:" << val2;        format_message << init_str;        string get_message=format_message.str();        cout << get_message << endl;         system("pause");        return 0;    }


上例输出:

 val1:512 

val2: 1024

well done

接下来我们来学习一下输入/输出的状态标志的相关知识,C++中负责的输入/输出的系统包括了关于每一个输入/输出操作的结果的记录信息。这些当前的状态信息被包含在io_state类型的对象中。io_state是一个枚举类型(就像open_mode一样),以下便是它包含的值。
goodbit 无错误
eofbit 已到达文件尾
failbit 非致命的输入/输出错误,可挽回
badbit 致命的输入/输出错误,无法挽回

有两种方法可以获得输入/输出的状态信息。一种方法是通过调用rdstate()函数,它将返回当前状态的错误标记。例如,假如没有任何错误,则rdstate()会返回goodbit.

  1. #include <iostream>    using namespace std;    int main()    {        int a;        cin >> a;        cout << cin.rdstate() << endl;        if(cin.rdstate()== istream::goodbit)        {            cout << "correct!";        }        if(cin.rdstate() == istream::failbit)        {            cout << "failed!";        }        system("pause");        return 0;    }

上例输出:0 correct!

另一种方法则是使用下面任何一个函数来检测相应的输入/输出状态:
bool bad();
bool eof();
bool fail();
bool good();

  1. #include <iostream>    using namespace std;    int main()    {        int a;        cin >> a;        cout << cin.rdstate() << endl;        if(cin.good())        {            cout << "correct!";        }        if(cin.fail())        {            cout << "failed!";        }        system("pause");        return 0;    }


如果错误发生,那么流状态既被标记为错误,你必须清除这些错误状态,以使你的程序能正确适当地继续运行。要清除错误状态,需使用clear()函数。此函数带一个参数,它是你将要设为当前状态的标志值。,只要将stream::goodbit作为实参。

  1. #include <iostream>    #include <string>    using namespace std;    int main()    {        int a;        cin >> a;        cout << cin.rdstate() << endl;        cin.setstate(iostream::failbit);        cout << cin.rdstate() << endl;        system("pause");        return 0;    }

输出:0 2 (其中goodbit为0,failbit为2)。