文件流操作之C++版

  昨天簡單介紹了一下C中的文件流操作,其實更強大、更復雜的操作還得看C++,畢竟C++是C的加強,不論是從功能還是效率上都比C高出一個檔次,而我們在實際的流操作中對C++的使用怕也是更加頻繁,所以接下來就重點講解下C++的文件流操作。

  那麼就先說說文件流的定義吧。文件流是以外存文件爲輸入/輸出對象的數據流。輸出文件流是從內存流向外存文件的數據,輸入文件流是從外存文件流向內存的數據。每一個文件流都有一個內存緩衝區與之對應。

與C一樣,C++的文件流操作也分爲同樣的三個部分。
(1)打開文件
(2)讀/寫文件
(3)關閉文件

在這之前先說下文件流的類:
(1) ifstream ifile:只輸入用,它是從istream 類派生的。
(2) ofstream ofile:只輸出用,它是從ostream 類派生的。
(3) fstream iofile:既輸入又輸出用,它是從iostream 類派生的。
即是說,如果你想要的操作只是從文件中讀數據,可這麼定義:
ifstream fin("...");

要寫入文件,則是:
ofstream fout("...");

如果既有讀操作,又是寫操作,就可以直接定義:
fstream fin("...");
fstream fout("...");

好了,知道了這些就可以進行文件的打開操作了。
打開文件有兩種方式,一種是自動打開,一種是調用open函數打開。
(1)自動打開:
fstream file("filename",iosmode);

(2)使用open函數打開:
fstream file;
file.open("filename",iosmode);

也可以用指針的形式打開:
fstream* file = new fstream;
file->open("filename",iosmode);

可以注意到,這裏的iosmode指的是打開文件的方式,和C一樣,C++中的文件流操作中的文件也是分成文本文件和二進制文件,不光是文件,打開方式也有幾種類型,下面介紹的這些只是我們平時可能會用到的,當然還有很多類型,只是平時很難會用到,所以就不再介紹了。

ios::in               以輸入方式打開文件
ios::out              以輸出方式打開文件(默認方式)
ios::app              以追加方式打開文件,數據寫到文件尾
ios::ate              打開一個存在文件,文件指針指向文件尾
ios::binary           以二進制方式打開文件
ios::in|ios::out      以輸入輸出方式打開文件
ios::in|ios::binary   以二進制方式打開一個輸入文件
ios::out|ios::binary  以二進制方式打開一個輸出文件
ios::binary|ios::app  以二進制方式追加打開一個文件

需要注意的是,一般打開文件的默認方式是打開文本文件,所以二進制文件必須顯式打開。
另外,在輸出的時候也要注意,默認的輸出方式是覆蓋之前的數據,所以如果要保存之前的數據的話,一定要記得以追加方式輸出啊,我之前就是因爲這個問題鬱悶了很久~!

關閉文件:
這個和C一樣,都是調用close()函數,即file.close();

然後就是我們最爲關心的流讀寫操作了,先介紹一下常用的i/o流成員函數。
1.輸入:
(1)get():讀取一個字符或一個字符串
這個函數我所不理解的是書上說它有三種形式,不帶參數,帶一個參數和帶三個參數,但我自己在用的時候用的都是不帶參數和帶兩個參數的,貌似都可以。
不帶參數的get()是從文件中讀取一個字符,而且包括空格,然後返回這個字符。

ifstream fin("test.txt",ios:in);
char ch;
while((ch=fin.get())!=EOF)
  cout.put(ch);

這樣就能把test中的字符一個一個讀取出來輸出屏幕上了,不過它每次只能讀一個字符。
帶一個參數的get(char* ch,int size)就是讀取一段固定長度的字符串。

ifstream fin("test.txt",ios::in);
char ch[100];
fin.get(ch,10);
cout<<ch;

這樣就能把test中一段長度爲10的字符串讀取出來並輸出到屏幕上,不過它只能讀取固定長度的字符串,如果事先不知道文件中有多大的數據,確實會有點不爽啊。

(2)getline():讀取一行字符串
這個函數和get()差不多,在我理解看來是有兩種用法,不帶參數和帶兩個參數。

ifstream fin("test.txt",ios::in);
char ch1[100],ch2[100];
ch1 = fin.getline();
cout<<ch1<,endl;
fin.getline(ch2,10);
cout<<ch2<<endl;

這樣都是把文件中的一行讀取出來並顯示到屏幕上,它的不足是不能區分一行中出現的不同類型的字符或整數。當然讀整數可以用 fin>>num 的方法把文件中的整數直接讀到num中。
其實將get()和getline()結合起來使用是一種不錯的選擇,如文件中的革一行保存的數據是一個學生的學號,姓名和地址。

ifstream fin("test.txt",ios::in);
int num;
char name[10];
char address[20];
fin>>num;
fin.get(name,10);
fin.getline(address,20);

這樣,就把一行中的不同信息都保存起來了。

(3)read():從文件中讀取特定字符的字節,這種方式特別適合二進制文件的讀取。
如果想要把一個對象保存在文件中,並以對象的方式讀取信息,那read()方式真的是太合適了。如想要讀取文件中一個學生的信息。

ifstream fin("test.txt",ios::binary);
Student s;
fin.read((char*)&s,sizeof(s));

這樣,不管文件中保存的數據有多少不同的類型,抑或根本不知道某一數據的長度,通過這種方式都可以把文件中的某一個學生對象信息保存在s對象中了。這裏因爲s是自定義數據類型,所以要先把它轉化成char* 類型。

2.輸出:
輸出的方法相對來說要少點,因爲輸出的過程相對也要簡單一點。
(1)put():向文件中寫入一個字符。

ofstream fout("test.txt",ios::out);
char ch[6]="hello";
int i=0;
whlie(ch[i]!=EOF)
  put(ch[i++]);

這樣就可以把字符串 hello 輸出到文件中了,不過它只能將字符一個一個輸出,很不方便。

(2)write():向文件寫入一定數量的字節,與read()一樣,這種方式也特別適合二進制文件的輸出。尤其是想要把一個對象保存到文件中時。學生類就不在這裏寫出來了。

ofstream fout("test.txt",ios::binary);
Student s(1,"jack","1000");
fout.write((char*)&s,sizeof(s));

這樣就把學生對象s以二進制的方式保存在文件中了。這裏有個問題需要注意,如果只是保存一個對象可能這樣寫,如果是想保存多條對象,就得稍微改改了。
ofstream fout("test.txt",ios::binary|ios::app);

這樣纔不會覆蓋之前的對象。

當然,其實輸出流還有一種更簡單的形式,就是用fout直接輸出。

int num;
char name[10];
char address[20];
cin>>num>>name>>address;
fout<<num<<name<<address;

如此也可以將數據寫入文件中,讀取時調用get()或是getline()函數就行了。

除了這些以外,C++中還有一種隨機文件的讀取,它可以從文件的任意位置隨機讀取數據。
這裏面的兩個重要函數就是seekg(n)和tellg()。
seekg(n)可以定位到文件的位置n,從這一點讀取或寫入數據。
tellg()則是返回當文件的指針值。

寫了這麼多,我想如果遇到文件流操作的問題,這些應該基本足以解決了吧。當然也希望能與大家分享更多的有關文件流的精髓。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章