IO类型间的关系:
类型ifstream和istringstream都继承自istream。因此,我们可以像使用istream对象来使用ifstream和istringstream对象,可以对一个ifstream或者istringstream对象调用getline函数,类型ofstream和ostringstream都继承ostream,因此,我们如何使用cout的,就可以同样地使用这些类型的对象.今天,我们只讨论fstream文件流
#include <fstream> ofstream //文件写操作,内存写入存储设备(文件) 输出流 ifstream //文件读操作,存储设备到内存. 输入流 fstream //读写操作,对打开的文件可进行读写. 前两者的结合
文件打开模式:
ios::in 读 ios::out 写 ios::w:app 从文件末尾开始写 ios::binary 二进制模式 ios::trunc 打开一个文件,然后清空内容 ios::ate 打开一个文件,将位置移动到文件尾.
指定模式有以下限制:
1.只可以对ofstream或者fstream对象设定out模式.
2.只可以ifstream或fstream对象设定为in模式.
3.只有out被设定时,才可以设定为trunc模式.
4.trunc没被设置,才能设置app。在app模式下,默认以写的方式打开.
5.以out模式打开的文件也会被清空,所以,要想保留文件中额内容,同时要指定app模式. 或同时指定in 模式.
ifstream默认以in模式打开,当文件不存在时,打开失败.当然,也可以以ios::out模式打开,这样虽然不会报错,但是,我们并不能向文件中写数据,也就是说,这样做,没有任何意义.
ofstream默认以out和trunc打开,也就是说,当文件存在时,会清空文件的内容,那么,怎样才能使其在文件末尾追加呢,上面提到过,我们可以给ofstream对象加in或app模式, 使其不会清空文件内容,如果,文件不存在,则创建文件.
文件指针:
ios::beg //文件头 ios::cur //当前位置 ios::end //文件尾
用到的函数:
#include <istream> istream& seekg(stream pos); istream& seekg(streamoff,ios::seekdir way); // 这两个函数是移动文件指针的位置,
tellg()函数和tellp函数:
#include <istream> streampos tellg(); //该成员函数应用于输入流指针的位置;
#include <ostream> streampos tellp(); //该成员函数用于返回输出流指针的位置;
看个例子:
#include<iostream> #include <fstream> using namespace std; int main(int argc,char *argv[]) { ifstream is("test.txt"); ofstream os("test1.txt"); if(is){ is.seekg(0,is.end); int length = is.tellg();//返回当前位置指针到文件开头的距离 is.seekg(0,is.beg); char *buffer = new char[length]; //开辟缓冲区 is.read(buffer,length); //把数据当成一个块来读 is.close(); os.write(buffer,length); //输出到文件test1.txt中 delete[] buffer; } return 0; }
rdbuf函数:(c++流操作-------->rdbuf())
我们使用STL编程的时候有时候会想到把一个流对象指向的内容用另一个流对象来输出,比如想把一个文件的内容输出到显示器上,我们可以用简单的两行代码来完成.
ifstream in("test.txt"); cout << in.rdbuf().
函数原型:
streambuf *rdbuf() const; //返回调用对象的 streambuf *rdbuf(streambuf * sb); //把调用该函数的流重定向到sb指向的流;
看个例子:
#include<iostream> #include <fstream> using namespace std; int main(int argc,char *argv[]) { streambuf *psbuf,*backup; ofstream filestr; filestr.open("test.txt"); backup=cout.rdbuf(); //恢复cout流时使用 psbuf=filestr.rdbuf(); cout.rdbuf(psbuf); //cout 重定向到filestr流; cout << "这句话会被输出到文件test.txt中"; cout.rdbuf(backup); //恢复cout流; cout << "这句话会被输出到显示器上"; return 0; }
get,put,getline函数:
通过标准输入设备向输入流输入一行字符串有两种方式:get函数和getline函数,两者都是类istream的对象cin的成员函数,下面我们来看看两者的区别。
getline函数:
getline()函数读取整行,他使用通过ENTER键输入的换行符来确定输入的末尾,但不保存换行符,相反,在存储字符串时,他用空值字符来替 换换行符。要调用该函数,可以使用cin.getline(arrayname,strnum),第一个参数表示用来存储输入行的数组名,第二个参数表示输入的字符数。如果字符数为20,则函数最多读取19个字符,余下的用来存储自动在结尾处添加的空值字符。
getline函数在读取指定数目的字符或遇到换行符时停止读取。
#include <string> istream getline(istream& is,string& str,char delim); istream getline(istream& is,string& str);
get函数:
get函数有几种变体,其中一种和getline很像,接收参数相同,解释参数的方式也相同,并且都读取到行尾,但get并不读取并丢弃换行符,而是将其留在输入队列中。
假设两次调用get():
cin.get(name1,size1);
cin.get(name2,size2);
由于第一次调用后,换行符将留在输入队列中,因此第二次调用时看到的第一个字符便是换行符,因此第二个get函数认为已到达行尾,而没有发现任何可读取的内容,即数组name2值为空。
解决方法是借助get(),无参数的函数。其功能是读取下一个字符。
cin.get(name1,size1);
cin.get();
cin.get(name2,size2);
注:cin.get(name,size)函数仍返回一个cin对象,因此上述代码可以写为cin.get(name1,size1).get();
put函数:
向流输出单个字符:比如cout.put('a');该函数的返回值仍然是一个cout对象,所以cout.put(21).put(23).......put('\n'),可以连续输出.