一.輸出檔案流成員函數
1.輸出資料流的open函數
要使用一個輸出檔案流(ofstream),必須在建構函式或open函數中把該流與一個特定的磁碟檔案關聯起來。在各種情況下,描述檔案的參量是相同的。
當你開啟一個與輸出資料流關聯.的檔案時,通常指定一個open_mode標誌,如下表所示。可以用按位OR(|)運算子組合這些標誌,它們作為列舉程式定義在ios類中。
表 輸出檔案流檔案開啟模式
標 志 功 能
ios::app 開啟一個輸出檔案用於在檔案尾添加資料
ios::ate 開啟一個現存檔案(用於輸入或輸出)並尋找到結尾
ios::in 開啟一個輸入檔案對於一個ofstream檔案,使用ios::in作為一個openmode可避免刪除一個現存檔案中現有的內容 ios::out 開啟二個檔案,用於輸出。對於所有ofstream對象,此模式是隱含指定的 ios::nocreate 如果一個檔案存在則開啟它,否則該操作失敗 i。
s::noreplace 如果一個檔案不存在則作為新檔案開啟它,如果檔案已存在,則該操作失敗
ios::trunc 開啟一個檔案,如果它已經存在則刪除其中原有的內容如果指定了ios::out,但沒有指定iOs::ate、iOs::app和ios::in,則隱含為此模式
ios::binary 以二進位模式開啟一個檔案(預設是文字模式)
有三個公用輸出資料流涉及模式選項:
•建立一個檔案,如果該檔案己存在,則刪除舊的版本:
ostream ofile("FILENAME");//預設模式是ios::out
ofstream ofile("FILENAME",ios::out);//與上一句等效
•添加記錄到一個現存檔案中,如果檔案不存在便建立一個新檔案:
ofstream ofile(“FiILENAME”,ios::app);
•使用同一個流先後開啟不同的檔案(在同一時刻只有一個是開啟的):
ofstream ofile();
ofile.open("FTILE1",ios::in) //開啟檔案FILEl
…// 向檔案FILEl
輸出 ofile.close(); //關閉FILEl
ofile.open("FILE2",ios::in); //開啟檔案FILE2
…// 向檔案FILE2輸出
ofile.close(); //關閉FILE2
//當對象ofile離開它的範圍時便消亡
2.put函數
put函數把一個字元寫到輸出資料流中,下面兩個語句預設是相同的,但第二個受該流的格式化參量的影響:
cout.put(‘A’); //精確地輸出一個字元
cout<<"A"; //輸出一個字元,但此前設定的寬度和填充方式在此起作用
3.write函數
write函數把一個記憶體中的一塊內容寫到一個輸出檔案流中,長度參數指出寫的位元組數。下面的例子建立一個輸出檔案流並將Date結構的二進位值寫入檔案:
例 向檔案輸出
#i nclude<fstream.h>
struct Date
{
int mo,da,yr;
};
void main()
{
Date dt={6,10,92};
ofstream tfile("date.dat",ios::binary);
tfile.write((char*)&dt,sizeof dt);
}
write函數當遇到Null 字元時並不停止,因此能夠寫入完整的類結構,該函數帶兩個參量,一個char指標(指向記憶體資料的起始地址)和一個所寫的位元組數。注意在該結構對象的地址之前需要char*做強制類型轉換。
4.seekp和tellp函數
一個輸出檔案流儲存一個內部指標指出下一次寫資料的位置。seekp成員函數設定這個指標,因此可以以隨機方式向磁碟檔案輸出。tellp成員函數返回該檔案位置指標值。
5.輸出資料流的close函數
close成員函數關閉與一個輸出檔案流關聯的磁碟檔案。檔案使用完畢後必須將其關閉以完成所有磁碟輸出。雖然ofstream解構函式(destructor)會自動完成關閉,但如果需要在同一流對象上開啟另外的檔案,就需要使用close函數。
如果建構函式或open成員函數開啟了該檔案,輸出資料流解構函式自動關閉一個流的檔案。
6.錯誤處理函數
錯誤處理成員函數的作用是在寫到一個流時進行錯誤處理。各函數及其功能如下表所示。
錯誤處理成員函數及其功能
函 數 功能及傳回值
bad 如果出現一個不可恢複的錯誤,則返回一個非0值
fail 如果出現一個不可恢複的錯誤或一個預期的條件,例如一個轉換錯誤或檔案未找到,用返回一個非0值。在用零參量調用clear之後可能經常恢複處理
good 如果沒有錯誤條件(不可恢複的或其他)和沒有設定檔案結尾標誌,則返回一個非0值
eof 遇到檔案結尾條件,則返回一個非0值
clear 設定內部錯誤狀態,如果用預設參量調用,則清除所有錯誤位
rdstate 返回當前錯誤狀態
! 運算子經過了重載,它與fail函數執行相同的功能,因此運算式if(! cout)等價於 if (cout.fail())。
void*()運算子也是經過重載的,與!運算子相反,因此運算式if(cout)等價於if(! cout.fail())。
void*()運算子不等價於good,因為它不檢測檔案結尾。
(四)二進位輸出檔案
最初設計流的目的是用於文本,因此預設的輸出模式是文本方式。在以文字模式輸出時,若遇到分行符號(十進位10),便自動被擴充為斷行符號分行符號(十進位13)。這種自動擴充有時可能出問題,請看下列程式:
#i nclude<fstream.h>
int iarray[2]={99,10};
void main()
{
ofstream os("test.dat");
os.write((char *)iarray,sizeof(iarray));
}
當執行程式,向檔案中輸出時,10會被自動轉換成13,然而這裡的轉換顯然不是我們需要的。要想解決這一問題,就要採用二進位模式輸出。使用二進位模式輸出時,其中所寫的字元是不轉換的。使用二進位模式輸出到檔案有下列幾種方法,
(1)以通常方式構造一個流,然後使用setmode成員函數,在檔案開啟後改變模式,例如:
ofstream ofs("test.dat");
ofs.setmode(filebuf::binary);
ofs.write((char*)iarray,4); //向二進位檔案中寫入4位元組資料
(2)使用ofstream建構函式中的模式參量指定二進位輸出模式,例如:
#i nclude<fstream.h>
#i nclude<fcntl.h>
#i nclude<io.h>
int iarray[2]={99,10};
void main()
{
ofstream ofs("test.dat",ios::binary);
ofs.write((char*)iarray,4); //向二進位檔案中寫入4位元組資料
}
(3)使用二進位操作符代替setmode成員函數:
ofs<<binary;
若使用text操作符便把流切換到文本轉換模式。
(4)使用open函數帶一個二進位模式標誌開啟檔案,例如:
filedesc fd=open("test.dat",OBINARY|OCREAT|OWRONLY);
ofstream ofs(fd);
ofs.write((char*)iarray,4); //向二進位檔案中寫入4位元組資料
二.輸入資料流成員函數
輸人流成員函數用於從磁碟檔案中輸入,這些成員函數包括:
•open函數
•get函數
•getline函數
•read函數
•seekg和tellg函數
•close函數
1.輸入資料流的open函數
如果要使用一個輸入檔案流(ifstream),必須在建構函式中或者使用open函數把該流與一個特定磁碟檔案關聯起來。無論哪種方式,參量是相同的。
當開啟與一個輸入資料流關聯的檔案時,通常要指定一個模式標誌。模式標誌如下表所示,該標誌可以用按位OR(|)運算子進行組合。
表 輸入檔案流檔案開啟模式
ios::in 開啟檔案用於輸入(預設)
ios::nocreate 如果檔案不存在,該函數失敗
ios::binary 以二進位模式(預設模式是文字模式)開啟檔案
注意:如果需要測試檔案是否存在,必須在開啟檔案時指定ios::nocreate模式,然後使用fail成員函數確定:
istream ifile("FILENAME",ios::nocreate);
if (ifile.fail())
//The file does not exist...
2.get函數
非格式化get函數的功能與提取運算子(>>)很相像,主要的不同點是get函數在讀人資料時包括空白字元,而提取運算子在預設情況下拒絕接受空白字元。
例 get函數應用舉例
#i nclude<iostream.h>
void main()
{
char ch;
while((ch=cin.get())!=EOF)
cout.put(ch);
}
運行時如果輸入:
abc xyz 123
則輸出:
abc xyz 123
3.getline函數
getline成員函數的功能是允許從輸人流中讀取多個字元,並且允許指定輸入終止字元(預設值是換行字元),在讀取完成後,從讀取的內容中刪除該終止字元。
例 為輸入資料流指定一個終止字元
本程式連續讀人一串字元,直到遇到字元‘t’時停止,字元個數最多不超過99個。
#i nclude<iostream.h>
void main()
{
char line[100];
cout<<"Type a 1ine terminated by "t""<<endl;
cin.getline(1ine,100,"t");
cout<<line;
}
4.read函數
read成員函數從一個檔案讀位元組到一個指定的儲存空間地區,由長度參數確定要讀的位元組數。如果給出長度參數,當遇到檔案結束或者在文字模式檔案中遇到檔案結束標記字元時讀結束。
例 從一個payroll檔案讀一個二進位記錄到一個結構中
#i nclude<io.h>
void main()
{
struct
{
double salary;
char name[23];
}employee;
ifstream is("payroll",ios::binary|ios::nocreate);
if (is)
{
is.read((char*)&employee,sizeof(employee));
cout<<employee.name<<" "<<employee.salary<<endl;
}
else
{
cout<<"ERROR:Cannot openfile"payroll"."<<endl;
}
}
這裡假設資料記錄是通過指定的結構嚴格格式化的,並且設有終止的斷行符號或換行字元。
5.seekg和tellg函數
在輸入檔案流中,保留著一個指向檔案中下一個將讀資料的位置的內部指標,可以用 seekg函數來設定這個指標。
例 用seekg函數設定位置指標
#i nclude<fstream.h>
void main()
{
char ch;
ifstream tfile("payroll",ios::binary | ios::nocreate);
if(tfile)
{
tfile.seekg(8);
while(tfile.good())
{
//遇到檔案結束或讀取操作失敗時結束讀操作
tfile.get(ch);
if (!ch)break; //如果沒有讀到則退出迴圈
cout<<ch;
}
}
else
{
cout<<"ERROR;Cannot open file "payroll"."<<endl;
}
}
使用seekg可以實現面向記錄的資料管理系統,用固定長度的記錄尺寸乘以記錄號便得到相對於檔案末尾的位元組位置,然後使用get讀這個記錄。
tellg成員函數返回當前檔案讀指標的位置,這個值是streampos類型,該typedef結構定義在iostream.h中。
例 讀一個檔案並顯示出其中空格的位置
#i nclude<fstream.h>
void main()
{
char ch;
ifstream tfile("payroll",ios::binary | ios::nocreate);
if (tfile)
{
while(tfile.good())
{
streampos here=tfile.tellg();
tfile.get(ch);
if(ch==" ")
cout<<"\nPosition"<<here<<"is a space";
}
}
else
{
cout<<"ERROR:Cannot open file "payroll"."<<endl;
}
}
6.輸入資料流的close函數
close成員函數關閉與一個輸入檔案流關聯的磁碟檔案。
雖然ifstream類的解構函式可以自動關閉檔案,但是如果需要使用同一流對象開啟另一檔案,則首先要用close函數關閉當前檔案。
四、輸入/輸出流
一個iostream對象可以是資料的源或目的。兩個重要的I/O流類都是從iostream派生的,它們是fstream和strstream。這些類繼承了前面描述的stream和ostream類的功能。
fstream類支援磁碟檔案的輸入和輸出。如果你需要在同一個程式中從一個特定磁碟檔案讀和寫到該磁碟檔案,可以構造一個fstream對象。一個istream對象是有兩個邏輯子流的單個流,兩個子流一個用於輸入,另一個用於輸出。詳細說明請讀者參考線上說明或運行庫參考手冊