版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第十章文件10.1文件概述10.2文件的打開與關(guān)閉10.3文件的讀/寫10.4文件的定位10.5程序設(shè)計舉例習(xí)題10.1文件概述10.1.1文件的概念磁盤文件在DOS管理中被定義為存儲在外部介質(zhì)上的程序或數(shù)據(jù)的集合,是一批邏輯上有聯(lián)系的數(shù)據(jù)(如一個程序、一批實驗數(shù)據(jù)、一篇文章或一幅圖像等)。每個文件都有一個文件名作為標識,每個文件在磁盤中的具體存放位置、格式都由操作系統(tǒng)中的文件系統(tǒng)管理,也就是說,操作系統(tǒng)是以文件為單位對程序或數(shù)據(jù)進行管理的。我們最熟悉的是編輯后存于磁盤上的源程序文件*.C,經(jīng)編譯后得到的目標文件*.OBJ,連接之后形成的可執(zhí)行文件*.EXE等。我們只需告訴操作系統(tǒng)一個文件名,就可利用DOS命令或Windows的資源管理器對文件進行讀、寫、刪除、拷貝、顯示或打印等工作。在C語言中文件的含義更為廣泛,不僅包含以上所述的磁盤文件,還包括一切能進行輸入/輸出的終端設(shè)備,它們被看成是設(shè)備文件。如鍵盤常稱為標準輸入文件,顯示器稱為標準輸出文件。文件是由磁盤文件和設(shè)備文件組成的。作為磁盤文件之一的數(shù)據(jù)文件是本章學(xué)習(xí)的主要對象。根據(jù)文件內(nèi)數(shù)據(jù)的組織形式,文件可分為文本(text)文件和二進制文件。文本文件又稱為ASCII碼文件,這種文件在磁盤中存放時每個字節(jié)存放一個字符的ASCII碼。ASCII碼文件可在屏幕上按字符顯示,文件的內(nèi)容可以通過編輯程序(如記事本等)進行建立和修改,人們能讀懂文件內(nèi)容。但是ASCII碼文件所占存儲空間較多,處理時要花費轉(zhuǎn)換時間(內(nèi)存中的二進制形式與ASCII碼之間的轉(zhuǎn)換)。二進制文件是將數(shù)據(jù)按其在內(nèi)存中的二進制形式直接存入文件。這種形式可以節(jié)省存儲空間,減少轉(zhuǎn)換時間,在讀/寫大批數(shù)據(jù)時速度較快,一般中間結(jié)果數(shù)據(jù)常用二進制文件保存。但二進制文件不能直接輸出字符形式,所以不便于閱讀。整數(shù)5678在兩種不同文件中的存儲形式如圖10.1所示。從圖中可看出,整數(shù)5678在ASCII碼文件中占用了4個字節(jié),而在二進制文件中只占用了2個字節(jié)。圖10-1整數(shù)在不同文件中的存儲形式10.1.2數(shù)據(jù)流在使用C語言編寫應(yīng)用程序時,也可以利用操作系統(tǒng)來處理以文件形式存放在磁盤上的數(shù)據(jù)。操作系統(tǒng)直接管理文件時,一般是將文件作為一個整體來處理的,例如拷貝文件、刪除文件等,而用C編寫的應(yīng)用程序往往要對文件的內(nèi)容進行處理。文件的內(nèi)容可能千變?nèi)f化,文件的大小也各不相同,那么如何處理文件中的數(shù)據(jù)呢?為此,C語言的輸入/輸出系統(tǒng)引入了“流”(stream)的概念:在編程者和文件(包括終端設(shè)備)之間提供了一種抽象的概念——數(shù)據(jù)流,這也是基于Windows編程(進行輸入/輸出)的基本概念,所以要深入理解數(shù)據(jù)流的概念。數(shù)據(jù)流是對數(shù)據(jù)輸入/輸出(I/O)行為的一種抽象。各種各樣的終端設(shè)備或磁盤文件的細節(jié)是非常復(fù)雜多樣的(例如磁盤文件既允許順序存取,又允許隨機存取,而作為終端的設(shè)備文件就只能順序存取),直接對它們編程將會非常繁瑣。引入數(shù)據(jù)流的概念有效地解決了這一難題。只要建立了輸入/輸出數(shù)據(jù)流,編程者在應(yīng)用程序中就不需要關(guān)心底層輸入/輸出設(shè)備或是任何磁盤文件的具體細節(jié)差異。程序中要輸入數(shù)據(jù),只需從輸入數(shù)據(jù)流中讀入;輸出數(shù)據(jù)只需向輸出數(shù)據(jù)流中寫出即可,這樣就使程序完全與具體硬件資源脫離了關(guān)系,也就是說數(shù)據(jù)流使C程序與具體系統(tǒng)完全不相關(guān),使C程序可以非常方便地移植。數(shù)據(jù)流可分為文字流和二進制流。一個文字流是一行行的字符,換行符表示這一行的結(jié)束。文字流中某些字符的變換由環(huán)境工具的需要來決定。例如一個換行符可以變換為回車換行兩個字符。因此所讀/寫的字符與外部設(shè)備中的數(shù)據(jù)沒有一一對應(yīng)的關(guān)系。一個二進制流是由與外部設(shè)備中的數(shù)據(jù)一一對應(yīng)的一系列字節(jié)組成的。使用中沒有字符翻譯過程,而且所讀/寫的字節(jié)數(shù)目也與外部設(shè)備中的數(shù)目相同。在一個程序開始執(zhí)行時,三個預(yù)定義的文字流:stdin(標準輸入)、stdout(標準輸出)和stderr(標準出錯)就被打開,有的系統(tǒng)還同時打開stdprn(標準打印機)和stdaux(標準輔助設(shè)備,大多數(shù)系統(tǒng)是控制臺)。對編程人員來說,所有的I/O通過流來進行。所有的流都一樣,都是一系列字符。文件I/O系統(tǒng)把流與文件,也就是與有I/O功能的外部設(shè)備連接起來。C語言的I/O庫函數(shù)把來自設(shè)備的源信息轉(zhuǎn)換到流之中,或反過來把流中的信息轉(zhuǎn)換給各設(shè)備。在C語言中,編程者只需記住流這個概念,只使用一個文件系統(tǒng)就可以完成全部的I/O操作。10.1.3C的文件系統(tǒng)及其與流的關(guān)系
C的文件系統(tǒng)可分為緩沖文件系統(tǒng)和非緩沖文件系統(tǒng)兩類。所謂緩沖文件系統(tǒng),又稱高級磁盤輸入/輸出系統(tǒng)。在調(diào)用這種文件處理函數(shù)時,會自動在用戶內(nèi)存區(qū)中為每一個正在使用的文件劃出一片存儲單元,稱為開辟一個緩沖區(qū)。設(shè)立緩沖區(qū)的原因是磁盤的讀/寫速度比內(nèi)存的處理速度要慢很多,而且磁盤驅(qū)動器是機電設(shè)備,定位精度比較差,所以磁盤數(shù)據(jù)存取要以扇區(qū)(磁盤上某磁道中的一個弧形段,通常存放固定數(shù)量的數(shù)據(jù))或者簇(由若干扇區(qū)組成)為單位。這樣就要求有一個緩沖區(qū)來作為文件數(shù)據(jù)輸入/輸出的中間站來協(xié)調(diào):從磁盤文件中讀取數(shù)據(jù)時,先將含有該數(shù)據(jù)的扇區(qū)或簇從磁盤文件以慢速讀到緩沖區(qū)中,然后再從緩沖區(qū)將數(shù)據(jù)快速送到應(yīng)用程序的變量中去。下次再讀數(shù)據(jù)時,首先判斷緩沖區(qū)中是否還有數(shù)據(jù),如果有,則直接從緩沖區(qū)中讀,否則就要從磁盤中再讀另一個扇區(qū)或簇。向磁盤中寫數(shù)據(jù)也一樣,數(shù)據(jù)總是先從內(nèi)存寫入緩沖區(qū)中,直到緩沖區(qū)寫滿之后才一起送到磁盤文件中。前面學(xué)過的getchar()函數(shù)是類似的緩沖輸入方式,讀者可參考第三章中的相應(yīng)程序單步跟蹤其執(zhí)行過程,體會緩沖文件的實質(zhì)。非緩沖文件系統(tǒng)又稱為低級磁盤輸入/輸出系統(tǒng)。系統(tǒng)不為這類文件自動提供文件緩沖區(qū),文件讀/寫函數(shù)也與緩沖文件系統(tǒng)不同。因其不是ANSIC規(guī)定的范圍,又用得不多,故本書只介紹緩沖文件系統(tǒng)的有關(guān)知識。
C語言中將緩沖文件看成是流式文件,即無論文件的內(nèi)容是什么,一律看成是由字符(文本文件)或字節(jié)(二進制文件)構(gòu)成的序列,即字符流。流式文件的基本單位是字節(jié),磁盤文件和內(nèi)存變量之間的數(shù)據(jù)均以字節(jié)為基礎(chǔ)。若實際數(shù)據(jù)的劃分是結(jié)構(gòu)體類型的數(shù)據(jù)塊,可通過一次讀/寫多個字節(jié)來實現(xiàn)。流式文件的好處也就是應(yīng)用數(shù)據(jù)流的好處,即對各種文件編程時不必去關(guān)心具體設(shè)備的復(fù)雜情況或各種磁盤文件的具體格式,只需單純地與數(shù)據(jù)流交換數(shù)據(jù)即可達到與各種具體設(shè)備交換數(shù)據(jù)或處理各種具體文件的目的。具體地講,讀一個字符即是從數(shù)據(jù)流中拷貝一個字符到內(nèi)存中;寫一個字符,就是將內(nèi)存中的一個字符拷貝到數(shù)據(jù)流中。至于數(shù)據(jù)真正從何處“流”來或“流”向何處,編程者只需在程序的最初將數(shù)據(jù)流與具體的硬件資源或磁盤文件聯(lián)系起來即可確定,其后的具體操作中編程者只需調(diào)用讀/寫函數(shù),而不必考慮具體設(shè)備或文件間的差異。這樣非常有利于編出統(tǒng)一的、易移植的程序。例如,我們從一開始學(xué)的輸入/輸出函數(shù),為什么可以直接調(diào)用scanf()函數(shù)從鍵盤讀入數(shù)據(jù),調(diào)用printf()函數(shù)就可以在CRT上顯示數(shù)據(jù)呢?程序里沒有任何參數(shù)提及鍵盤或顯示器,這是因為程序運行之初即自動打開三個文件將數(shù)據(jù)流定向于鍵盤和顯示器(這是系統(tǒng)的缺省設(shè)置),這樣應(yīng)用程序就可以直接實現(xiàn)從鍵盤輸入數(shù)據(jù)或向顯示器輸出數(shù)據(jù)了。磁盤文件不同于設(shè)備文件之處在于必須在程序中調(diào)用打開函數(shù)來打開文件,即用一個文件打開操作使數(shù)據(jù)流和一個特定的文件發(fā)生聯(lián)系。一旦一個文件被正確打開,應(yīng)用程序就可以通過一個數(shù)據(jù)流與該文件之間交換信息。完成任務(wù)后,應(yīng)用程序又必須關(guān)閉文件,即用一個文件關(guān)閉操作切斷數(shù)據(jù)流與磁盤文件間的聯(lián)系,也就是使數(shù)據(jù)流脫離一個具體的文件。10.1.4文件指針一般緩沖文件操作有三個必需的步驟:
(1)在使用文件前要調(diào)用打開函數(shù)將文件打開,若打開失敗,則返回一個空指針;若打開正常,可以得到一個文件指針,并利用它繼續(xù)對文件操作。
(2)可調(diào)用各種有關(guān)函數(shù),利用該指針對文件進行具體處理,一般要對文件進行讀或?qū)懖僮鳌?/p>
(3)在文件用完時,應(yīng)及時調(diào)用關(guān)閉函數(shù)來關(guān)閉文件,切斷數(shù)據(jù)流,防止數(shù)據(jù)遺失或誤操作破壞文件內(nèi)容。緩沖文件系統(tǒng)中,關(guān)鍵的概念是文件指針。通常,由于文件中的數(shù)據(jù)很多,因此讀/寫時應(yīng)該指明對哪個數(shù)據(jù)進行操作。流式文件中采用的方法是設(shè)立一個專門用來存放文件讀/寫位置的變量,稱為當前工作指針。在對某文件開始進行操作時,將當前工作指針的值設(shè)置為0,表示文件從頭開始讀(寫);每次讀(寫)之后,自動將當前工作指針的值加上本次讀(寫)的字節(jié)數(shù),作為下次讀(寫)的位置。從前面的介紹可以看出,要對一個文件進行操作,除了要設(shè)當前工作指針,還必須管理緩沖區(qū)。實際上,在頭文件stdio.h中,定義了一個名為FILE的類型,包含了所有與文件操作有關(guān)的數(shù)據(jù)成員,這個文件類型是文件處理的基礎(chǔ)。文件類型FILE不是C語言的新類型,它是用typedef定義出來的有關(guān)文件信息的一種結(jié)構(gòu)體類型。如TurboC的stdio.h文件中有如下的定義:
typedefstruct
{
short level;/*緩沖區(qū)“滿”或“空”的程度*/unsigned flags;/*文件狀態(tài)標志*/char fd;/*文件描述符*/unsignedchar hold;/*如無緩沖區(qū)不讀取字符*/short bsize;/*緩沖區(qū)的大小*/unsignedchar *buffer;/*數(shù)據(jù)緩沖區(qū)的位置*/unsignedchar *curp;/*當前工作指針*/unsigned istemp;/*臨時文件,指示器*/short token;/*用于有效性檢查*/
}FILE;有了FILE類型之后,可以定義文件型指針。如“FILE*fp;”,fp是一個文件型的指針,將指向某個文件,即指向FILE型的結(jié)構(gòu)體型變量中有關(guān)文件的信息,通過這些信息能夠找到與它相關(guān)的文件。如果有n個文件,一般應(yīng)設(shè)n個文件指針,使它們分別指向n個文件,以實現(xiàn)對文件的訪問。實際上,文件指針就可以理解為數(shù)據(jù)流。設(shè)了一個文件型指針,然后將打開文件時返回的具體文件的首地址賦給該指針,就建立起了程序與文件間的數(shù)據(jù)流,后續(xù)的程序?qū)υ撐募囊磺胁僮髦恍栳槍Υ酥羔槻僮鳎疵撾x具體的文件,只面向數(shù)據(jù)流操作。在完成具體的文件操作之后,關(guān)閉文件時,就切斷了該文件型指針與文件間的聯(lián)系,此指針不再指向那個文件,也就是切斷了該文件的數(shù)據(jù)流。10.2文件的打開與關(guān)閉
C語言中,沒有輸入/輸出語句,對文件的操作都是用庫函數(shù)來實現(xiàn)的。下面將介紹緩沖文件系統(tǒng)的打開和關(guān)閉函數(shù)。10.2.1文件的打開(fopen()函數(shù))
打開函數(shù)fopen()的調(diào)用方式是:
FILE*fp;
fp=fopen(文件名,使用文件方式);例如,
fp=fopen("A1.DAT","r");它表示,要打開名字為A1.DAT的文件,使用文件方式為“讀入”,fopen()函數(shù)帶回指向A1.DAT文件的指針并賦給fp,這樣fp就和A1.DAT相聯(lián)系了,或者說,fp指向A1.DAT文件??梢钥闯觯诖蜷_一個文件時,將給編譯系統(tǒng)通知以下三個信息:
(1)需要打開的文件名。也就是準備訪問的文件的名字。
(2)使用文件的方式(讀還是寫等)。
(3)讓哪一個指針變量指向被打開的文件。文件使用方式見表10.1。表10.1文件使用方式說明:
(1)表中所用字母分別為單詞read,write,append,binary或其組合詞的首字母。
(2)用"r"方式打開的文件只能用于從該文件中讀出數(shù)據(jù)至計算機的內(nèi)存變量中,而不能用作向該文件寫數(shù)據(jù)。而且該文件應(yīng)該已經(jīng)存在,不能用"r"方式打開一個并不存在的文件。
(3)用"w"方式打開的文件只能用于向該文件寫數(shù)據(jù),而不能用來從文件中讀出數(shù)據(jù)。如果原來不存在該文件,則在打開時新建立一個按指定名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件刪去,然后重新建立一個新文件。
(4)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用"a"方式打開,但此時該文件必須存在,否則將得到出錯信息。打開時,位置指針將移到文件末尾。
(5)用"r+","w+","a+"方式打開的文件可以用來輸入和輸出數(shù)據(jù)。用"r+"方式時該文件應(yīng)該已經(jīng)存在,以便能向計算機輸入數(shù)據(jù)。用"w+"方式則新建立一個文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用"a+"方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加也可以讀。
(6)如果不能實現(xiàn)“打開”的任務(wù),fopen()函數(shù)將會帶回一個出錯信息。出錯的原因可能是用"r"方式打開了一個并不存在的文件、磁盤出故障或磁盤已滿無法建立新文件等。此時,fopen()函數(shù)將帶回一個空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的程序段打開一個文件:
if((fp=fopen("filel","r"))==NULL){
printf("Cannotopenthisfile\n");
exit(0);
}即先檢查打開操作是否正確,如果有錯就在終端上輸出“Cannotopenthisfile”。
exit()函數(shù)的作用是關(guān)閉所有文件,終止正執(zhí)行的程序。待程序員檢查出錯原因,修改后再運行。
(7)用以上方式可以打開文本文件或二進制文件,這是標準C的規(guī)定,用同一種緩沖文件系統(tǒng)來處理文本文件和二進制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能,例如有的只能用"r"、"w"、"a"方式,有的C版本不用"r+"、"w+"、"a+",而用"rw"、"wr"、"ar"等。請讀者注意所用系統(tǒng)的規(guī)定。
(8)在用文本文件向計算機輸入數(shù)據(jù)時,將回車換行符轉(zhuǎn)換為一個換行符,在輸出時把換行符轉(zhuǎn)換成回車和換行兩個字符。在用二進制文件時,不進行這種轉(zhuǎn)換,內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對應(yīng)。10.2.2文件的關(guān)閉(fclose()函數(shù))
在使用完一個文件后應(yīng)該調(diào)用fclose()函數(shù)關(guān)閉文件。
fclose()函數(shù)的調(diào)用格式為fclose(文件指針)。例如“fclose(fp);”就表示把指針fp所指的文件關(guān)閉了,也就是斷開了打開文件時建立的數(shù)據(jù)流——fp與具體文件的聯(lián)系,即不能再通過fp對某個具體文件進行操作。如果在程序終止之前不關(guān)閉文件,將可能丟失緩沖區(qū)中最后一批未處理的數(shù)據(jù),因為fclose()函數(shù)的調(diào)用不僅釋放文件指針,還刷新緩沖區(qū)。fclose()函數(shù)將緩沖區(qū)中可能遺留的未裝滿送走的數(shù)據(jù)輸入內(nèi)存或輸出至磁盤文件,以確保數(shù)據(jù)不丟失。當然,程序結(jié)束時會自動關(guān)閉文件,但用完文件后及時關(guān)閉是一個好的編程習(xí)慣。
fclose()函數(shù)也返回一個值:0表示順利返回,非0表示關(guān)閉錯誤。10.3文件的讀/寫10.3.1fputc()函數(shù)和fgetc()函數(shù)
fputc()函數(shù)的調(diào)用形式為:
fputc(ch,fp);該函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中。其中ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針,它是從fopen()函數(shù)得到的返回值。fputc()函數(shù)也帶回一個值,如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF。EOF是在stdio.h文件中定義的符號常量,值為-1。
fgetc()函數(shù)的調(diào)用形式為:
ch=fgetc(fp);該函數(shù)的作用是從指定文件讀入一個字符,該文件必須是以讀或讀/寫方式打開的。其中fp為文件型指針,指向所打開備讀的文件;ch為字符變量,接收fgetc()函數(shù)帶回的字符。如果在執(zhí)行fgetc()讀字符時遇到文件結(jié)束符,函數(shù)則返回一個文件結(jié)束標志EOF,可以利用它來判斷是否讀完了文件中的數(shù)據(jù)。如想從一個磁盤文件按順序讀入字符并在屏幕上顯示出來,可編程為:
while((ch=fgetc(fp))!=EOF)
putchar(ch);注意,EOF不是可輸出字符,因此在屏幕上顯示不出來。由于字符的ASCII碼不可能出現(xiàn)-1,因此EOF定義為-1是合適的。當讀入的字符值等于-1(即EOF)時,表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件。現(xiàn)在標準C已允許用緩沖文件系統(tǒng)處理二進制文件,讀入某一個字節(jié)中的二進制數(shù)據(jù)的值有可能是-1,而這又恰好是EOF的值。這就出現(xiàn)了讀入有用數(shù)據(jù)卻被處理為“文件結(jié)束”的情況,即終止符設(shè)置不恰當。為了解決這個問題,標準C提供了一個feof()函數(shù)來判斷文件是否真的結(jié)束。feof(fp)用來測試fp所指向的文件當前狀態(tài)是否為“文件結(jié)束”,如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真),否則為0(假)。例如,順序讀入一個二進制文件中的數(shù)據(jù)的程序段如下:
while(!feof(fp))
{
c=fgetc(fp);
}當未遇文件結(jié)束時,feof(fp)的值為0,!feof(fp)為1,讀入一個字節(jié)的數(shù)據(jù)賦給變量c(接著可做其它處理),之后再求feof(fp)函數(shù),循環(huán)工作直到文件結(jié)束,feof(fp)值變?yōu)?,!feof(fp)值為0,結(jié)束while循環(huán)。這種方法也適用于文本文件。在掌握了以上幾種函數(shù)以后,可以編制一些簡單的使用文件的程序,下面是一文件建立的例子。
例10.1
建立一個磁盤文件,將鍵入的回車前的若干個字符逐個寫入該文件。
#include<stdio.h>
voidmain()
{
FILE*fp;
charch,filename[13];
printf("\nInputthefile\′sname:");
gets(filename);/*注1*/
if((fp=fopen(filename,"w"))==NULL){
printf("Cannotopenthefile\n");
exit(0);
}
printf("Inputthecharacterstothefile:\n");
while((ch=getchar())!=′\n′)
/*注2*/{
fputc(ch,fp); /*注3*/
putchar(ch); /*注4*/}fclose(fp);
}運行情況如下:
Inputthefile′sname:fileex1.dat↙
(注1要求的輸入磁盤文件名)
Inputthecharacterstothefile:
Whatinsidethefile↙
(注2要求的鍵入一個字符串)
Whatinsidethefile
(注4輸出到顯示器上的字符串,與寫入文件的內(nèi)容一樣,以資核對)程序運行之后,可以查看文件目錄,將多出一個名為fileex1.dat的數(shù)據(jù)文件,可用DOS命令將其內(nèi)容打印出來:
typefileex1.dat↙Whatinsidethefile (由注3行循環(huán)寫入的)由上例可以看出,文件指針就是通向文件的數(shù)據(jù)流。當打開一個文件,執(zhí)行fp=fopen(…)時,就將一個數(shù)據(jù)流與該文件聯(lián)系起來,其后對文件的操作都是對此文件指針fp的操作,即“脫離”具體文件,只通過對數(shù)據(jù)流的操作,完成對相應(yīng)文件的操作。此后的程序直到執(zhí)行相應(yīng)的fclose(fp)函數(shù)之時,文件指針fp相當于該具體文件的全權(quán)代表。執(zhí)行相應(yīng)的fclose()函數(shù)時,關(guān)閉文件,就切斷了該文件與此數(shù)據(jù)流之間的聯(lián)系。10.3.2fgets()函數(shù)和fputs()函數(shù)
fgets()函數(shù)是從指定文件讀入一個字符串,其調(diào)用形式如下:
fgets(str,n,fp);該函數(shù)的功能是從fp指向的文件讀入n-1個字符,并把它們放到字符數(shù)組str(也可以是字符指針)中,如果在讀入n-1個字符結(jié)束之前遇到換行符或EOF,讀入即結(jié)束。字符串讀入在最后加一個′\0′字符,fgets()函數(shù)返回值為str的首地址。
fputs()函數(shù)是向指定的文件輸出一個字符串,其調(diào)用形式如下:
fputs(str,fp);該函數(shù)將字符串輸出到fp指向的文件。其中str可以是字符串常量、字符數(shù)組名或字符指針。若函數(shù)調(diào)用成功,返回0,否則返回非0值。例如:fputs(“China”,fp);即將字符串"China"輸出到fp指向的文件。這兩個函數(shù)類似以前介紹過的gets()和puts()函數(shù),只是fgets()和fputs()函數(shù)以指定的文件作為讀/寫對象。10.3.3fprintf()函數(shù)和fscanf()函數(shù)
fprintf()函數(shù)、fscanf()函數(shù)與printf()和scanf()函數(shù)的作用類似,都是格式化讀/寫函數(shù)。前二者的讀/寫對象是磁盤文件,而后二者是終端設(shè)備。所以前二者函數(shù)調(diào)用參數(shù)中要多出一代表文件的文件指針。一般調(diào)用方式為:
fprintf(文件指針,控制字符串,參量表);
fscanf(文件指針,控制字符串,參量表);下例說明了這兩種函數(shù)的用法。例10.2
按格式鍵入字符型、整型、實型各一數(shù),寫入文件dform.dat,再讀出送顯。
#include<stdio.h>
voidmain()
{
inti,i1;
charch,ch1;
floatf,f1;
FILE*fp;
printf("\nInputchif:");
scanf("%c%d%f",&ch,&i,&f);
if((fp=fopen(“dform.dat”,“w”))==NULL)
/*注1*/
{
printf("Cannotopenthefile\n");
exit(0);
}
fprintf(fp,"%c%5d%4.1f",ch,i,f);/*注2*/
fclose(fp);/*注3*/
if((fp=fopen("dform.dat","r"))==NULL)
{
printf("Cannotopenthefile\n");
exit(0);
}
fscanf(fp,"%c%d%f",&ch1,&i1,&f1);
printf("%c%5d%4.1f",ch1,i1,f1);
fclose(fp);
}分析:注1行為寫打開文本文件dform.dat;注2行即為格式化寫函數(shù)調(diào)用,將三數(shù)寫入文件;注3行是在寫操作完成之后關(guān)閉文件,若無此關(guān)閉操作,三數(shù)只能留在緩沖區(qū)中,而未真正寫到文件中。雖然其后接著要讀同一個文件,也仍然由fp指向,但此前的fp指向的是為寫打開的dform.dat,要想讀此文件,還必須再以讀的形式打開,再由fp指向。程序運行情況:
Inputchif:a22.2↙ (提示及輸入)
a└┘└┘└┘└┘22.2 (屏幕顯示)
dform.dat中的內(nèi)容同屏顯。10.3.4fread()函數(shù)和fwrite()函數(shù)用fprintf()和fscanf()函數(shù)對磁盤文件讀/寫,使用方便,容易理解,但由于在輸入時要將ASClI碼轉(zhuǎn)換為二進制形式,在輸出時又要將二進制形式轉(zhuǎn)換成字符,花費時間比較多。再者,格式讀/寫只能面向數(shù)據(jù)項,對于結(jié)構(gòu)體類型的變量則要一個一個成員地輸入/輸出,程序編寫比較繁瑣。因此,當文件內(nèi)的數(shù)據(jù)以結(jié)構(gòu)體類型組織或內(nèi)存與磁盤頻繁交換數(shù)據(jù)時,最好不用fprintf()和fscanf()函數(shù),而用成對讀/寫函數(shù)fread()和fwrite()。
fread()和fwrite()的一般調(diào)用形式為:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);其中:buffer是一個地址。對fread來說,它是讀入數(shù)據(jù)將要存放處的地址。對fwrite()來說,是要輸出數(shù)據(jù)的地址。
size是要讀/寫的一個數(shù)據(jù)塊的字節(jié)數(shù)。
count是要進行讀/寫數(shù)據(jù)塊的個數(shù)。
fp是文件指針,指向待讀或?qū)懙奈募?。如果函?shù)調(diào)用成功,則函數(shù)返回為count的值,即輸入或輸出數(shù)據(jù)項的完整個數(shù);否則出錯。如果文件以二進制形式打開,則用fread()和fwrite()函數(shù)就可以讀/寫任何類型的信息。例如:
fread(f,4,2,fp);其中,f是一個實型數(shù)組名。一個實型變量占4個字節(jié)。這個函數(shù)從fp所指向的文件讀入2次(每次4個字節(jié))數(shù)據(jù),存儲到數(shù)組f中。下面以一文件建立為例說明一結(jié)構(gòu)體變量的整體寫入。例10.3
建立一個有關(guān)工人工資的數(shù)據(jù)文件。
#include<stdio.h>
#defineSIZE6
structstaff
{
charname[10];
intsalary;
intcost;
}worker[SIZE];
voidsavef()
{
FILE*fp;
inti;
if((fp=fopen("work.dat","wb"))==NULL)
/*以二進制只寫方式打開文件*/{
printf("Cannotopenthefile\n");
return;
}
for(i=0;i<SIZE;i++)
if(fwrite(&worker[i],sizeof(structstaff),1,fp)!=1)
/*寫數(shù)據(jù)到文件中*/
printf("Filewriteerror\n");
fclose(fp);
}
voidmain(){
inti;
printf("\nInput%dworker\′snamesalarycost:\n",SIZE);
for(i=0;i<SIZE;i++)
scanf("%s%d%d",worker[i].name,&worker[i].salary,&worker[i].cost);
savef();
}10.4文件的定位前面已介紹過:文件中有一個位置指針指向下一個要讀的數(shù)據(jù),稱為當前工作指針。每讀/寫完一個數(shù)據(jù),該位置指針即自動向后移動一個數(shù)據(jù)的位置,指向了下一個要讀/寫的數(shù)據(jù),這就是順序讀/寫。但實際處理中,常常要求隨機讀/寫或多次反復(fù)讀/寫,就要調(diào)用有關(guān)函數(shù),強制位置指針指向其它位置。10.4.1rewind()函數(shù)
rewind()函數(shù)可以強制使當前工作指針指向文件的開頭。一般在要重新從頭讀/寫文件時使用。如下例,在讀了文件dfr.dat一遍送顯示器后,文件的位置指針已移到文件的最后,為了重新讀一遍再寫到文件dfw.dat中,必須先執(zhí)行一次rewind()函數(shù),才能正確讀出。例10.4
將已建好的文件dfr.dat的內(nèi)容順序讀一遍送顯示器,再讀一遍復(fù)制到文件dfw.dat中。
#include<stdio.h>
voidmain()
{
inti;
charch;
floatf,f1;
FILE*fp1,*fp2;
if((fp1=fopen("dfr.dat","r"))==NULL)
/*以只讀方式打開文本文件*/
{
printf("Cannotopenthefileforreading\n");
exit(0);
}
if((fp2=fopen("dfw.dat","w"))==NULL)
/*以只寫方式打開文本文件*/
{
printf("Cannotopenthefileforwriting\n");
exit(0);
}
fscanf(fp1,"%c%d%f",&ch,&i,&f);
printf("%c,%5d,%4.1f\n",ch,i,f);
rewind(fp1);
/*使當前文件的位置指針指向文件開頭*/
fscanf(fp1,"%c%d%f",&ch,&i,&f1);
fprintf(fp2,“%c%d%f”,ch,i,f1);
/*寫數(shù)據(jù)到文件中*/
fclose(fp1);
fclose(fp2);
}若將例10.2產(chǎn)生的dform.dat拷貝為dfr.dat,則程序運行后,屏幕顯示為:
a,2,2.2所建立的dfw.dat文件的內(nèi)容為a22.200000。10.4.2fseek()函數(shù)利用fseek()函數(shù)可以控制文件位置的指針進行隨機讀/寫。
fseek()函數(shù)的調(diào)用形式如下:
fseek(文件類型指針,位移量,起始點);起始點可按表10.2中規(guī)定的方式取值,既可以用標準C規(guī)定的常量名,也可以用對應(yīng)的數(shù)字。位移量指從起始點向前移動的字節(jié)數(shù)。
fseek()函數(shù)一般用于二進制文件,因為文本文件要發(fā)生字符轉(zhuǎn)換,計算位置時容易發(fā)生混亂。下面是一個文件隨機讀/寫的例子。表10.2指針起始點的表示例10.5
將例10.3形成的職工數(shù)據(jù)文件中的第1、3、5個工人的信息讀出、送顯。
#include<stdio.h>
#defineSIZE6
structstaff
{
charname[10];
intsalary;
intcost;
}worker[SIZE];
voidmain()
{
FILE*fp;
inti;
if((fp=fopen("work.dat","rb"))==NULL)/*以只讀方式打開二進制文件*/
{
printf("Cannotopenthefile\n");
exit(0);
}
for(i=0;i<SIZE;i++,i++)
{
fseek(fp,i*sizeof(structstaff),0);
fread(&worker[i],sizeof(structstaff),1,fp);
/*從文件中讀出的數(shù)據(jù)存入結(jié)構(gòu)體數(shù)組*/
printf(“%s%d%d\n”,worker[i].name,
worker[i].salary,worker[i].cost);
}
fclose(fp);
}若形成work.dat文件時的輸入數(shù)據(jù)為:
Li11100100↙
Li21200200↙
Li31300300↙
Li41400400↙
Li51500500↙
Li61600600↙則此程序的運行結(jié)果為:
Li11100100
Li31300300
Li5150050010.4.3ftell()函數(shù)
ftell()函數(shù)的作用是得到流式文件中位置指針的當前位置,用相對于文件開頭的位移量來表示。由于文件的位置指針經(jīng)常移動,往往不易搞清其當前位置,用ftell()函數(shù)可以返回其當前位置,若返回-1L,表示函數(shù)調(diào)用出錯。例如:
i=ftell(fp);
if(i==-1L)printf("error\n");有關(guān)文件的處理函數(shù)還有很多,讀者可查看附錄二。初學(xué)者往往感到文件編程難,主要是對文件的概念比較陌生所致。其實,文件的編程并不是很難,只是在過去的數(shù)據(jù)處理程序的前后加上些有關(guān)文件的“套子”罷了,而這些有關(guān)文件的“套子”是相對程式化的。如果掌握了本書前面各章節(jié)的知識,只需記住有關(guān)文件的函數(shù),理解文件的概念和處理步驟,再加上些出錯處理即可較容易地進行文件編程。10.5程序設(shè)計舉例
例10.6
若文件number.dat中存放了一組整數(shù),試編程統(tǒng)計并輸出文件中正整數(shù)、零和負整數(shù)的個數(shù)。
#include<stdio.h>
voidmain()
{
FILE*fp;
intp=0,n=0,z=0,temp;
fp=fopen(“number.dat”,“r”);
/*以只讀方式打開文本文件*/
if(fp==NULL)
printf("filenotfound!\n");
else
{
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年淋浴房產(chǎn)品研發(fā)與技術(shù)合作合同
- 2024年度企業(yè)員工培訓(xùn)與職業(yè)發(fā)展咨詢合同3篇
- 2024年汽車修理廠合伙業(yè)務(wù)拓展合作協(xié)議3篇
- 2024年度食堂肉類冷鏈配送與儲存服務(wù)合同2篇
- 2024年度圖書進出口貿(mào)易及采購合同
- 2024年度采光井工程節(jié)能監(jiān)測協(xié)議2篇
- 2024年度鐵礦石采購與長期合作協(xié)議2篇
- 鐵粉清運勞務(wù)合同范例
- 新學(xué)期工作計劃模板4篇范文
- 社團活動計劃錦集七篇資料
- SN國際貨運代理公司海運業(yè)務(wù)流程優(yōu)化研究
- 預(yù)防小火亡人主題班會
- 消防行車安全教育課件
- 海洋平臺深水管道高效保溫技術(shù)
- 《新疆大學(xué)版學(xué)術(shù)期刊目錄》(人文社科)
- 充電樁維保投標方案
- 《如何寫文獻綜述》課件
- 肛瘺LIFT術(shù)式介紹
- 通過《古文觀止》選讀了解古代文學(xué)的社會功能與價值
- 語言本能:人類語言進化的奧秘
- 職業(yè)生涯規(guī)劃(圖文)課件
評論
0/150
提交評論