詳解C++編程中的文件流與字符串流
C++文件流類與文件流對象
文件流是以外存文件為輸入輸出對象的數(shù)據(jù)流。輸出文件流是從內(nèi)存流向外存文件的數(shù)據(jù),輸入文件流是從外存文件流向內(nèi)存的數(shù)據(jù)。每一個文件流都有一個內(nèi)存緩沖區(qū)與之對應(yīng)。
請區(qū)分文件流與文件的概念,不用誤以為文件流是由若干個文件組成的流。文件流本身不是文件,而只是以文件為輸入輸出對象的流。若要對磁盤文件輸入輸出,就必須通過文件流來實現(xiàn)。
在C++的I/O類庫中定義了幾種文件類,專門用于對磁盤文件的輸入輸出操作。
除了標準輸入輸出流類istream、ostream和iostream類外,還有3個用于文件操作的文件類:
- ifstream類,它是從istream類派生的,用來支持從磁盤文件的輸入。
- ofstream類,它是從ostream類派生的,用來支持向磁盤文件的輸出。
- fstream類,它是從iostream類派生的,用來支持對磁盤文件的輸入輸出。
要以磁盤文件為對象進行輸入輸出,必須定義一個文件流類的對象,通過文件流對象將數(shù)據(jù)從內(nèi)存輸出到磁盤文件,或者通過文件流對象從磁盤文件將數(shù)據(jù)輸入到內(nèi)存。
其實在用標準設(shè)備為對象的輸入輸出中,也是要定義流對象的,如cin、cout就是流對象,C++是通過流對象進行輸入輸出的。由于cin、cout已在iostream.h中事先定義,所以用戶不需自己定義。在用磁盤文件時,由于情況各異,無法事先統(tǒng)一定義,必須由用戶自己定義。此外,對磁盤文件的操作是通過文件流對象(而不是cin和cout)實現(xiàn)的。文件流對象是用文件流類定義的,而不是用istream和ostream類來定義的。可以用下面的方法建立一個輸出文件流對象:
ofstream outfile;
如同在頭文件iostream中定義了流對象cout —樣,現(xiàn)在在程序中定義了outfile為 ofstream類(輸出文件流類)的對象。但是有一個問埋還未解決:在定義 cout 時已將它和標準輸出設(shè)備(顯示器)建立關(guān)聯(lián),而現(xiàn)在雖然建立了一個輸出文件流對象,但是還未指定它向哪一個磁盤文件輸出,需要在使用時加以指定。
C++對字符串流的讀寫
文件流是以外存文件為輸入輸出對象的數(shù)據(jù)流,字符串流不是以外存文件為輸入輸出的對象,而以內(nèi)存中用戶定義的字符數(shù)組(字符串)為輸入輸出的對象,即將數(shù)據(jù)輸出到內(nèi)存中的字符數(shù)組,或者從字符數(shù)組(字符串)將數(shù)據(jù)讀入。字符串流也稱為內(nèi)存流。
字符串流也有相應(yīng)的緩沖區(qū),開始時流緩沖區(qū)是空的。如果向字符數(shù)組存入數(shù)據(jù),隨著向流插入數(shù)據(jù),流緩沖區(qū)中的數(shù)據(jù)不斷增加,待緩沖區(qū)滿了(或遇換行符),一起存入字符數(shù)組。如果是從字符數(shù)組讀數(shù)據(jù),先將字符數(shù)組中的數(shù)據(jù)送到流緩沖區(qū),然后從緩沖區(qū)中提取數(shù)據(jù)賦給有關(guān)變量。
在字符數(shù)組中可以存放字符,也可以存放整數(shù)、浮點數(shù)以及其他類型的數(shù)據(jù)。在向字符數(shù)組存入數(shù)據(jù)之前,要先將數(shù)據(jù)從二進制形式轉(zhuǎn)換為ASCII代碼,然后存放在緩沖區(qū), 再從緩沖區(qū)送到字符數(shù)組。從字符數(shù)組讀數(shù)據(jù)時,先將字符數(shù)組中的數(shù)據(jù)送到緩沖區(qū),在賦給變量前要先將ASCII代碼轉(zhuǎn)換為二進制形式??傊?,流緩沖區(qū)中的數(shù)據(jù)格式與字符數(shù)組相同。這種情況與以標準設(shè)備(鍵盤和顯示器)為對象的輸入輸出是類似的,鍵盤和顯示器都是按字符形式輸入輸出的設(shè)備,內(nèi)存中的數(shù)據(jù)在輸出到顯示器之前,先要轉(zhuǎn)換為 ASCII碼形式,并送到輸出緩沖區(qū)中。從鍵盤輸入的數(shù)據(jù)以ASCII碼形式輸入到輸入緩沖區(qū),在賦給變量前轉(zhuǎn)換為相應(yīng)變量類型的二進制形式,然后賦給變量。對于字符串流的輸入輸出的情況,如不清楚,可以從對標準設(shè)備的輸入輸出中得到啟發(fā)。
文件流類有ifstream,ofstream和fstream,而字符串流類有istrstream,ostrstream和strstream。文件流類和字符串流類都是ostream,istream和iostream類的派生類,因此對它們的操作方法是基本相同的。向內(nèi)存中的一個字符數(shù)組寫數(shù)據(jù)就如同向文件寫數(shù)據(jù)一樣,但有3點不同:
輸出時數(shù)據(jù)不是流向外存文件,而是流向內(nèi)存中的一個存儲空間。輸入時從內(nèi)存中的存儲空間讀取數(shù)據(jù)。在嚴格的意義上說,這不屬于輸入輸出,稱為讀寫比較合適。 因為輸入輸出一般指的是在計算機內(nèi)存與計算機外的文件(外部設(shè)備也視為文件)之間 的數(shù)據(jù)傳送。但由于C++的字符串流采用了 C++的流輸入輸出機制,因此往往也用輸入和輸出來表述讀寫操作。
字符串流對象關(guān)聯(lián)的不是文件,而是內(nèi)存中的一個字符數(shù)組,因此不需要打開和關(guān)閉文件。
每個文件的最后都有一個文件結(jié)束符,表示文件的結(jié)束。而字符串流所關(guān)聯(lián)的字符數(shù)組中沒有相應(yīng)的結(jié)束標志,用戶要指定一個特殊字符作為結(jié)束符,在向字符數(shù)組寫入全部數(shù)據(jù)后要寫入此字符。
字符串流類沒有open成員函數(shù),因此要在建立字符串流對象時通過給定參數(shù)來確立字符串流與字符數(shù)組的關(guān)聯(lián)。即通過調(diào)用構(gòu)造函數(shù)來解決此問題。建立字符串流對象的方法與含義如下。
建立輸出字符串流對象
ostrstream類提供的構(gòu)造函數(shù)的原型為:
ostrstream::ostrstream(char *buffer,int n,int mode=ios::out);
buffer是指向字符數(shù)組首元素的指針,n為指定的流緩沖區(qū)的大?。ㄒ话氵x與字符數(shù)組的大小相同,也可以不同),第3個參數(shù)是可選的,默認為ios::out方式。可以用以下語句建立輸出字符串流對象并與字符數(shù)組建立關(guān)聯(lián):
ostrstream strout(ch1,20);
作用是建立輸出字符串流對象strout,并使strout與字符數(shù)組ch1關(guān)聯(lián)(通過字符串流將數(shù)據(jù)輸出到字符數(shù)組ch1),流緩沖區(qū)大小為20。
建立輸入字符串流對象
istrstream類提供了兩個帶參的構(gòu)造函數(shù),原型為:
istrstream::istrstream(char *buffer); istrstream::istrstream(char *buffer,int n);
buffer是指向字符數(shù)組首元素的指針,用它來初始化流對象(使流對象與字符數(shù)組建立關(guān)聯(lián))??梢杂靡韵抡Z句建立輸入字符串流對象:
istrstream strin(ch2);
作用是建立輸入字符串流對象strin,將字符數(shù)組ch2中的全部數(shù)據(jù)作為輸入字符串流的內(nèi)容。
istrstream strin(ch2,20);
流緩沖區(qū)大小為20,因此只將字符數(shù)組ch2中的,20個字符作為輸入字符串流的內(nèi)容。
建立輸入輸出字符串流對象
strstream類提供的構(gòu)造函數(shù)的原型為:
strstream::strstream(char *buffer,int n,int mode);
可以用以下語句建立輸入輸出字符串流對象:
strstream strio(ch3,sizeof(ch3),ios::in|ios::out);
作用是建立輸入輸出字符串流對象,以字符數(shù)組ch3為輸入輸出對象,流緩沖區(qū)大小與數(shù)組ch3相同。
以上個字符串流類是在頭文件strstream中定義的,因此程序中在用到istrstream、ostrstream和strstream類時應(yīng)包含頭文件strstream(在GCC中,用頭文件strstream)。
[例] 將一組數(shù)據(jù)保存在字符數(shù)組中。
#include <strstream> using namespace std; struct student { int num; char name[20]; float score; }; int main( ) { student stud[3]={1001,"Li",78,1002,"Wang",89.5,1004,"Fun",90}; char c[50]; //用戶定義的字符數(shù)組 ostrstream strout(c,30); //建立輸出字符串流,與數(shù)組c建立關(guān)聯(lián),緩沖區(qū)長 for(int i=0;i<3;i++) //向字符數(shù)組c寫個學(xué)生的數(shù)據(jù) strout<<stud[i].num<<stud[i].name<<stud[i].score; strout<<ends; //ends是C++的I/O操作符,插入一個'\\0' cout<<"array c:"<<c<<endl; //顯示字符數(shù)組c中的字符 }
運行時在顯示器上的輸出如下:
array c: 1001Li781002Wang89.51004Fun90
以上就是字符數(shù)組c中的字符??梢钥吹剑?br /> 1) 字符數(shù)組c中的數(shù)據(jù)全部是以ASCII代碼形式存放的字符,而不是以二進制形式表示的數(shù)據(jù)。
2) 在建立字符串流strout時指定流緩沖區(qū)大小為30字節(jié),與字符數(shù)組c的大小不同,這是允許的,這時字符串流最多可以傳送30個字符給字符數(shù)組c。請思考:如果將流 緩沖區(qū)大小改為10字節(jié),即:
ostrstream.strout( c ,10);
運行情況會怎樣?流緩沖區(qū)只能存放10個字符,將這10個字符寫到字符數(shù)組c中。運行時顯示的結(jié)果是:
1001Li7810
字符數(shù)組c中只有10個有效字符。一般都把流緩沖區(qū)的大小指定與字符數(shù)組的大小 相同。
3) 字符數(shù)組c中的數(shù)據(jù)之間沒有空格,連成一片,這是由輸出的方式?jīng)Q定的。如果以后想將這些數(shù)據(jù)讀回賦給程序中相應(yīng)的變量,就會出現(xiàn)問題,因為無法分隔兩個相鄰的數(shù)據(jù)。為解決此問題,可在輸出時人為地加入空格。如
for(int i=0;i<3;i++) strout<<" "<<stud[i].num<<" "<<stud[i].name<<" "<<stud[i].score;
同時應(yīng)修改流緩沖區(qū)的大小,以便能容納全部內(nèi)容,今改為字節(jié)。這樣,運行時將輸出:
1001 Li 78 1002 Wang 89.5 1004 Fun 90
再讀入時就能清楚地將數(shù)據(jù)分隔開。
[例] 在一個字符數(shù)組c中存放了個整數(shù),以空格相間隔,要求將它們放到整型數(shù)組中,再按大小排序,然后再存放回字符數(shù)組c中。
#include <strstream> using namespace std; int main( ) { char c[50]="12 34 65 -23 -32 33 61 99 321 32"; int a[10],i,j,t; cout<<"array c:"<<c<<endl; //顯示字符數(shù)組中的字符串 istrstream strin(c,sizeof(c)); //建立輸入串流對象strin并與字符數(shù)組c關(guān)聯(lián) for(i=0;i<10;i++) strin>>a[i]; //從字符數(shù)組c讀入個整數(shù)賦給整型數(shù)組a cout<<"array a:"; for(i=0;i<10;i++) cout<<a[i]<<" "; //顯示整型數(shù)組a各元素 cout<<endl; for(i=0;i<9;i++) //用起泡法對數(shù)組a排序 for(j=0;j<9-i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} ostrstream strout(c,sizeof(c)); //建立輸出串流對象strout并與字符數(shù)組c關(guān)聯(lián) for(i=0;i<10;i++) strout<<a[i]<<" "; //將個整數(shù)存放在字符數(shù)組c strout<<ends; //加入'\\0' cout<<"array c:"<<c<<endl; //顯示字符數(shù)組c return 0; }
運行結(jié)果如下:
array c: 12 34 65 -23 -32 33 61 99 321 32(字符數(shù)組c原來的內(nèi)容) array a: 12 34 65 -23 -32 33 61 99 321 32 (整型數(shù)組a的內(nèi)容) array c: -32 –12 32 33 34 61 65 99 321 (字符數(shù)組c最后的內(nèi)容)
對字符串流的幾點說明:
1) 用字符串流時不需要打開和關(guān)閉文件。
2) 通過字符串流從字符數(shù)組讀數(shù)據(jù)就如同從鍵盤讀數(shù)據(jù)一樣,可以從字符數(shù)組讀入字符數(shù)據(jù),也可以讀入整數(shù)、浮點數(shù)或其他類型數(shù)據(jù)。如果不用字符串流,只能從字符數(shù)組逐個訪問字符,而不能按其他類型的數(shù)據(jù)形式讀取數(shù)據(jù)。這是用字符串流訪問字符數(shù)組的優(yōu)點,使用方便靈活。
3) 程序中先后建立了兩個字符串流strin和strout,與字符數(shù)組c關(guān)聯(lián)。strin從字符數(shù)組c中獲取數(shù)據(jù),strout將數(shù)據(jù)傳送給字符數(shù)組。分別對同一字符數(shù)組進行操作。甚至可以對字符數(shù)組交叉進行讀寫,輸入字符串流和輸出字符串流分別有流指針指示當(dāng)前位 置,互不干擾。
4) 用輸出字符串流向字符數(shù)組c寫數(shù)據(jù)時,是從數(shù)組的首地址開始的,因此更新了 數(shù)組的內(nèi)容。
5) 字符串流關(guān)聯(lián)的字符數(shù)組并不一定是專為字符串流而定義的數(shù)組,它與一般的字符數(shù)組無異,可以對該數(shù)組進行其他各種操作。
通過以上對字符串流的介紹,大家可以看到:與字符串流關(guān)聯(lián)的字符數(shù)組相當(dāng)于內(nèi)存中的臨時倉庫,可以用來存放各種類型的數(shù)據(jù)(以ASCII形式存放),在需要時再從中讀回來。它的用法相當(dāng)于標準設(shè)備(顯示器與鍵盤),但標準設(shè)備不能保存數(shù)據(jù),而字符數(shù)組中的內(nèi)容可以隨時用ASCII字符輸出。它比外存文件使用方便,不必建立文件(不 需打開與關(guān)閉),存取速度快。但它的生命周期與其所在的模塊(如主函數(shù))相同,該模塊的生命周期結(jié)束后,字符數(shù)組也不存在了。因此只能作為臨時的存儲空間。
相關(guān)文章
C/C++中一次性執(zhí)行多個DOS命令的實現(xiàn)思路
在C語言中執(zhí)行DOS命令的方法很多,在這就不一給大家一一介紹了,本文重點給大家介紹C/C++中一次性執(zhí)行多個DOS命令的實現(xiàn)思路,需要的朋友參考下2017-12-12