1. 程式人生 > >IO相關2(文件輸入輸出)

IO相關2(文件輸入輸出)

argc run 打開文件 read str 下一個 當前位置 ace 位置

除了繼承自 iostream 類型的行為之外,fstream 中定義的類型還增加了一些新的成員來管理與流相關的文件。我們可以對 fstream,ifstream 和 ofstream 對象調用這些操作,但不能對其他 IO 類型調用這些操作:

1     fstream fstrm;//創建一個未綁定的文件流.fstream是頭文件fstream中定義的一個類型
2     fstream fstrm1(s);//創建一個fstream,並打開名未s的文件.s可以是string類型或者是一個指向c風格字符串的指針.這些構造函數都是explicit的。默認的文件模式mode依賴於fstream的類型
3
fstream fstrm2(s, mode);//與前一個構造函數類似,但指定mode打開文件 4 fstrm.open(s);//打開名為s的文件,並將文件與fstrm綁定.s可以是一個string或一個指向c風格字符串的指針.默認的文件mode依賴於fstream的類型.返回void 5 fstrm.close();//關閉fstrm綁定的文件.返回void 6 fstrm.is_open();//返回一個bool值,指出與fstrm關聯的文件是否成功打開且尚未關閉

使用文件流對象:

ifstream in(ifile);//構造一個ifstram並打開給定文件
ofstream out;//輸出文件流未關聯到任何文件

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4 
 5 char const *filename = "D:\\code\\c++\\ac27.text";
 6 
 7 string str;
 8 
 9 int main(void){
10     ofstream file(filename);
11     if(!file) return 0;
12     file << "hello world!" << endl;
13     file.close();
14 15 ifstream out; 16 out.open(filename); 17 while(out >> str){ 18 cout << str << endl; 19 } 20 out.close(); 21 return 0; 22 }

用 fstream 代替 iostream&

在要求使用基類對象的地方,我們可以用繼承類型的對象來替代。因此,如果一個函數接受一個 ostream& 參數,我們在調用這個函數時,可以傳遞給他一個 ofstream 對象,對 istream& 和 ifstream 也是類似的:

 1 #include "Sales_data.h"
 2 #include <iostream>
 3 #include <fstream>
 4 using namespace std;
 5 
 6 int main(int argc, char const *argv[]){
 7     ifstream input(argv[1]);
 8     ofstream output(argv[2]);
 9     Sales_data total;
10     if(read(input, total)){
11         Sales_data trans;
12         while(read(input, trans)){
13             if(total.isbn() == trans.isbn()) total += trans;
14             else{
15                 print(output, total) << endl;
16                 total = trans;
17             }
18         }
19         print(output, total) << endl;
20     }else cerr << "NO data?" << endl;
21     return 0;
22 }

read 和 print 兩個函數定義時指定的形參分別時 istream& 和 ostream&,但我們可以傳遞 fstream 對象。

自動構造和析構:

考慮這樣一個程序,它的 main 函數接受一個要處理的文件列表:

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4 
 5 const string gel("D:\\code\\c++\\");
 6 
 7 void process(ifstream &input){
 8     string str;
 9     input >> str;
10     cout << str << endl;
11 }
12 
13 int main(int argc, char const *argv[]){
14     for(int i = 1; i < argc; i++){
15         const string filename = (char)(i - 1 + a) + (string)".txt";
16         // cout << filename << endl;
17         ofstream output(gel + filename);
18         output << filename << endl;
19         // output.close();//fstream對象離開其作用域時,與之聯系的文件自動關閉(close會自動調用)
20     }
21 
22     //對每個傳遞給程序的文件執行循環操作
23     for(auto p = argv + 1; p != argv + argc; ++p){
24         ifstream input(*p);//創建輸出流並打開文件
25         if(input) process(input);
26         else cerr << "couldn‘t open: " + string(*p) << endl;
27         // input.close();
28     }
29     return 0;
30 }

因為 output 和 input 是局部變量,它在每個循環步中都要創建和銷毀一次。當一個 fstream 對象離開其作用域時,與之對應的文件會自動關閉。在下一步循環中,它們會再次被創建。當一個 fstream 對象被銷毀時,close 會自動調用。

文件模式:

每個流都有一個關聯的文件模式,用來指出如何使用文件:

in      以讀方式打開

out     以寫方式打開

app     每次寫操作前均定位到文件末尾

ate      打開文件後立即定位到文件末尾

trunc     截斷文件

binary     以二進制方式進行IO

指定文件模式有如下限制:

1.只可以對 ofstream 或 fstream 對象設定 out 模式。

2.只可以對 ifstream 或 fstream 對象設定 in 模式。

3.只有當 out 也被設定時才可以設定 trunc 模式。

4.只要 trunc 沒被設定,就可以設定 app 模式。在 app 模式下,即使沒有顯示指定 out 模式,文件也總是以輸出方式被打開。

5.默認情況下,即使我們沒有指定 trunc,以 out 模式打開的文件也會被截斷。為了保留以 out 模式打開的文件內容,我們必須同時指定 app 模式,這樣才會以追加的模式寫到文件末尾:或者同時指定 in 模式,即打開文件同時進行讀寫操作。

6.ate 和 binaty 模式可用於任何類型的文件流對象,且可以與其他任何文件模式組合使用。

每個文件流類型都定義了一個默認的文件模式,當我們未指定文件模式時,就使用此默認模式。ifsream 關聯的文件默認以 in 模式打開,ofstream 關聯的文件默認以 out 模式打開,fstream 關聯的文件默認以 in 和 out 模式打開。

對流的操作:

對輸入流操作:seekg()與tellg()
對輸出流操作:seekp()與tellp()


下面以輸入流函數為例介紹用法:
seekg() 是對輸入文件定位,它有兩個參數:第一個參數是偏移量,第二個參數是基地址。
對於第一個參數,可以是正負數值,正的表示向後偏移,負的表示向前偏移。而第二個參數可以是:
ios::beg:表示輸入流的開始位置
ios::cur:表示輸入流的當前位置
ios::end:表示輸入流的結束位置
tellg() 函數不需要帶參數,它返回當前定位指針的位置,也代表著輸入流的大小。

 1 #include <iostream>
 2 #include <fstream>
 3 using namespace std;
 4 
 5 const char *filename = "D:\\code\\c++\\ac27.text";//該文件中存儲了abcd四個字符
 6 
 7 int main(void){
 8     long l, m;
 9     ifstream in(filename, ios::in | ios::binary | ios::ate);//加了ate參數,此時get指針在文件末尾(‘\0‘)的下一個位置
10     l = in.tellg();
11     in.seekg(0, ios::end);//將get指針移動到文件末尾下一個位置
12     m = in.tellg();//得到get指針當前的位置
13     in.close();
14     cout << l << endl;//輸出6
15     cout << "size of " << filename;
16     cout << " is " << (m - 1) << " byset.\n";//m-1為5
17     return 0;
18 }

對於輸出流操作:seekp()與tellp()用法是一樣的。

IO相關2(文件輸入輸出)