1. 程式人生 > >C++fstream讀寫檔案

C++fstream讀寫檔案

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'),可以連續輸出.