




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第十章文件10.1文件概述10.2文件的打開與關閉10.3文件的讀/寫10.4文件的定位10.5程序設計舉例習題10.1文件概述10.1.1文件的概念磁盤文件在DOS管理中被定義為存儲在外部介質上的程序或數據的集合,是一批邏輯上有聯系的數據(如一個程序、一批實驗數據、一篇文章或一幅圖像等)。每個文件都有一個文件名作為標識,每個文件在磁盤中的具體存放位置、格式都由操作系統中的文件系統管理,也就是說,操作系統是以文件為單位對程序或數據進行管理的。我們最熟悉的是編輯后存于磁盤上的源程序文件*.C,經編譯后得到的目標文件*.OBJ,連接之后形成的可執行文件*.EXE等。我們只需告訴操作系統一個文件名,就可利用DOS命令或Windows的資源管理器對文件進行讀、寫、刪除、拷貝、顯示或打印等工作。在C語言中文件的含義更為廣泛,不僅包含以上所述的磁盤文件,還包括一切能進行輸入/輸出的終端設備,它們被看成是設備文件。如鍵盤常稱為標準輸入文件,顯示器稱為標準輸出文件。文件是由磁盤文件和設備文件組成的。作為磁盤文件之一的數據文件是本章學習的主要對象。根據文件內數據的組織形式,文件可分為文本(text)文件和二進制文件。文本文件又稱為ASCII碼文件,這種文件在磁盤中存放時每個字節存放一個字符的ASCII碼。ASCII碼文件可在屏幕上按字符顯示,文件的內容可以通過編輯程序(如記事本等)進行建立和修改,人們能讀懂文件內容。但是ASCII碼文件所占存儲空間較多,處理時要花費轉換時間(內存中的二進制形式與ASCII碼之間的轉換)。二進制文件是將數據按其在內存中的二進制形式直接存入文件。這種形式可以節省存儲空間,減少轉換時間,在讀/寫大批數據時速度較快,一般中間結果數據常用二進制文件保存。但二進制文件不能直接輸出字符形式,所以不便于閱讀。整數5678在兩種不同文件中的存儲形式如圖10.1所示。從圖中可看出,整數5678在ASCII碼文件中占用了4個字節,而在二進制文件中只占用了2個字節。圖10-1整數在不同文件中的存儲形式10.1.2數據流在使用C語言編寫應用程序時,也可以利用操作系統來處理以文件形式存放在磁盤上的數據。操作系統直接管理文件時,一般是將文件作為一個整體來處理的,例如拷貝文件、刪除文件等,而用C編寫的應用程序往往要對文件的內容進行處理。文件的內容可能千變萬化,文件的大小也各不相同,那么如何處理文件中的數據呢?為此,C語言的輸入/輸出系統引入了“流”(stream)的概念:在編程者和文件(包括終端設備)之間提供了一種抽象的概念——數據流,這也是基于Windows編程(進行輸入/輸出)的基本概念,所以要深入理解數據流的概念。數據流是對數據輸入/輸出(I/O)行為的一種抽象。各種各樣的終端設備或磁盤文件的細節是非常復雜多樣的(例如磁盤文件既允許順序存取,又允許隨機存取,而作為終端的設備文件就只能順序存取),直接對它們編程將會非常繁瑣。引入數據流的概念有效地解決了這一難題。只要建立了輸入/輸出數據流,編程者在應用程序中就不需要關心底層輸入/輸出設備或是任何磁盤文件的具體細節差異。程序中要輸入數據,只需從輸入數據流中讀入;輸出數據只需向輸出數據流中寫出即可,這樣就使程序完全與具體硬件資源脫離了關系,也就是說數據流使C程序與具體系統完全不相關,使C程序可以非常方便地移植。數據流可分為文字流和二進制流。一個文字流是一行行的字符,換行符表示這一行的結束。文字流中某些字符的變換由環境工具的需要來決定。例如一個換行符可以變換為回車換行兩個字符。因此所讀/寫的字符與外部設備中的數據沒有一一對應的關系。一個二進制流是由與外部設備中的數據一一對應的一系列字節組成的。使用中沒有字符翻譯過程,而且所讀/寫的字節數目也與外部設備中的數目相同。在一個程序開始執行時,三個預定義的文字流:stdin(標準輸入)、stdout(標準輸出)和stderr(標準出錯)就被打開,有的系統還同時打開stdprn(標準打印機)和stdaux(標準輔助設備,大多數系統是控制臺)。對編程人員來說,所有的I/O通過流來進行。所有的流都一樣,都是一系列字符。文件I/O系統把流與文件,也就是與有I/O功能的外部設備連接起來。C語言的I/O庫函數把來自設備的源信息轉換到流之中,或反過來把流中的信息轉換給各設備。在C語言中,編程者只需記住流這個概念,只使用一個文件系統就可以完成全部的I/O操作。10.1.3C的文件系統及其與流的關系
C的文件系統可分為緩沖文件系統和非緩沖文件系統兩類。所謂緩沖文件系統,又稱高級磁盤輸入/輸出系統。在調用這種文件處理函數時,會自動在用戶內存區中為每一個正在使用的文件劃出一片存儲單元,稱為開辟一個緩沖區。設立緩沖區的原因是磁盤的讀/寫速度比內存的處理速度要慢很多,而且磁盤驅動器是機電設備,定位精度比較差,所以磁盤數據存取要以扇區(磁盤上某磁道中的一個弧形段,通常存放固定數量的數據)或者簇(由若干扇區組成)為單位。這樣就要求有一個緩沖區來作為文件數據輸入/輸出的中間站來協調:從磁盤文件中讀取數據時,先將含有該數據的扇區或簇從磁盤文件以慢速讀到緩沖區中,然后再從緩沖區將數據快速送到應用程序的變量中去。下次再讀數據時,首先判斷緩沖區中是否還有數據,如果有,則直接從緩沖區中讀,否則就要從磁盤中再讀另一個扇區或簇。向磁盤中寫數據也一樣,數據總是先從內存寫入緩沖區中,直到緩沖區寫滿之后才一起送到磁盤文件中。前面學過的getchar()函數是類似的緩沖輸入方式,讀者可參考第三章中的相應程序單步跟蹤其執行過程,體會緩沖文件的實質。非緩沖文件系統又稱為低級磁盤輸入/輸出系統。系統不為這類文件自動提供文件緩沖區,文件讀/寫函數也與緩沖文件系統不同。因其不是ANSIC規定的范圍,又用得不多,故本書只介紹緩沖文件系統的有關知識。
C語言中將緩沖文件看成是流式文件,即無論文件的內容是什么,一律看成是由字符(文本文件)或字節(二進制文件)構成的序列,即字符流。流式文件的基本單位是字節,磁盤文件和內存變量之間的數據均以字節為基礎。若實際數據的劃分是結構體類型的數據塊,可通過一次讀/寫多個字節來實現。流式文件的好處也就是應用數據流的好處,即對各種文件編程時不必去關心具體設備的復雜情況或各種磁盤文件的具體格式,只需單純地與數據流交換數據即可達到與各種具體設備交換數據或處理各種具體文件的目的。具體地講,讀一個字符即是從數據流中拷貝一個字符到內存中;寫一個字符,就是將內存中的一個字符拷貝到數據流中。至于數據真正從何處“流”來或“流”向何處,編程者只需在程序的最初將數據流與具體的硬件資源或磁盤文件聯系起來即可確定,其后的具體操作中編程者只需調用讀/寫函數,而不必考慮具體設備或文件間的差異。這樣非常有利于編出統一的、易移植的程序。例如,我們從一開始學的輸入/輸出函數,為什么可以直接調用scanf()函數從鍵盤讀入數據,調用printf()函數就可以在CRT上顯示數據呢?程序里沒有任何參數提及鍵盤或顯示器,這是因為程序運行之初即自動打開三個文件將數據流定向于鍵盤和顯示器(這是系統的缺省設置),這樣應用程序就可以直接實現從鍵盤輸入數據或向顯示器輸出數據了。磁盤文件不同于設備文件之處在于必須在程序中調用打開函數來打開文件,即用一個文件打開操作使數據流和一個特定的文件發生聯系。一旦一個文件被正確打開,應用程序就可以通過一個數據流與該文件之間交換信息。完成任務后,應用程序又必須關閉文件,即用一個文件關閉操作切斷數據流與磁盤文件間的聯系,也就是使數據流脫離一個具體的文件。10.1.4文件指針一般緩沖文件操作有三個必需的步驟:
(1)在使用文件前要調用打開函數將文件打開,若打開失敗,則返回一個空指針;若打開正常,可以得到一個文件指針,并利用它繼續對文件操作。
(2)可調用各種有關函數,利用該指針對文件進行具體處理,一般要對文件進行讀或寫操作。
(3)在文件用完時,應及時調用關閉函數來關閉文件,切斷數據流,防止數據遺失或誤操作破壞文件內容。緩沖文件系統中,關鍵的概念是文件指針。通常,由于文件中的數據很多,因此讀/寫時應該指明對哪個數據進行操作。流式文件中采用的方法是設立一個專門用來存放文件讀/寫位置的變量,稱為當前工作指針。在對某文件開始進行操作時,將當前工作指針的值設置為0,表示文件從頭開始讀(寫);每次讀(寫)之后,自動將當前工作指針的值加上本次讀(寫)的字節數,作為下次讀(寫)的位置。從前面的介紹可以看出,要對一個文件進行操作,除了要設當前工作指針,還必須管理緩沖區。實際上,在頭文件stdio.h中,定義了一個名為FILE的類型,包含了所有與文件操作有關的數據成員,這個文件類型是文件處理的基礎。文件類型FILE不是C語言的新類型,它是用typedef定義出來的有關文件信息的一種結構體類型。如TurboC的stdio.h文件中有如下的定義:
typedefstruct
{
short level;/*緩沖區“滿”或“空”的程度*/unsigned flags;/*文件狀態標志*/char fd;/*文件描述符*/unsignedchar hold;/*如無緩沖區不讀取字符*/short bsize;/*緩沖區的大小*/unsignedchar *buffer;/*數據緩沖區的位置*/unsignedchar *curp;/*當前工作指針*/unsigned istemp;/*臨時文件,指示器*/short token;/*用于有效性檢查*/
}FILE;有了FILE類型之后,可以定義文件型指針。如“FILE*fp;”,fp是一個文件型的指針,將指向某個文件,即指向FILE型的結構體型變量中有關文件的信息,通過這些信息能夠找到與它相關的文件。如果有n個文件,一般應設n個文件指針,使它們分別指向n個文件,以實現對文件的訪問。實際上,文件指針就可以理解為數據流。設了一個文件型指針,然后將打開文件時返回的具體文件的首地址賦給該指針,就建立起了程序與文件間的數據流,后續的程序對該文件的一切操作只需針對此指針操作,即脫離具體的文件,只面向數據流操作。在完成具體的文件操作之后,關閉文件時,就切斷了該文件型指針與文件間的聯系,此指針不再指向那個文件,也就是切斷了該文件的數據流。10.2文件的打開與關閉
C語言中,沒有輸入/輸出語句,對文件的操作都是用庫函數來實現的。下面將介紹緩沖文件系統的打開和關閉函數。10.2.1文件的打開(fopen()函數)
打開函數fopen()的調用方式是:
FILE*fp;
fp=fopen(文件名,使用文件方式);例如,
fp=fopen("A1.DAT","r");它表示,要打開名字為A1.DAT的文件,使用文件方式為“讀入”,fopen()函數帶回指向A1.DAT文件的指針并賦給fp,這樣fp就和A1.DAT相聯系了,或者說,fp指向A1.DAT文件??梢钥闯?,在打開一個文件時,將給編譯系統通知以下三個信息:
(1)需要打開的文件名。也就是準備訪問的文件的名字。
(2)使用文件的方式(讀還是寫等)。
(3)讓哪一個指針變量指向被打開的文件。文件使用方式見表10.1。表10.1文件使用方式說明:
(1)表中所用字母分別為單詞read,write,append,binary或其組合詞的首字母。
(2)用"r"方式打開的文件只能用于從該文件中讀出數據至計算機的內存變量中,而不能用作向該文件寫數據。而且該文件應該已經存在,不能用"r"方式打開一個并不存在的文件。
(3)用"w"方式打開的文件只能用于向該文件寫數據,而不能用來從文件中讀出數據。如果原來不存在該文件,則在打開時新建立一個按指定名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件刪去,然后重新建立一個新文件。
(4)如果希望向文件末尾添加新的數據(不希望刪除原有數據),則應該用"a"方式打開,但此時該文件必須存在,否則將得到出錯信息。打開時,位置指針將移到文件末尾。
(5)用"r+","w+","a+"方式打開的文件可以用來輸入和輸出數據。用"r+"方式時該文件應該已經存在,以便能向計算機輸入數據。用"w+"方式則新建立一個文件,先向此文件寫數據,然后可以讀此文件中的數據。用"a+"方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加也可以讀。
(6)如果不能實現“打開”的任務,fopen()函數將會帶回一個出錯信息。出錯的原因可能是用"r"方式打開了一個并不存在的文件、磁盤出故障或磁盤已滿無法建立新文件等。此時,fopen()函數將帶回一個空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的程序段打開一個文件:
if((fp=fopen("filel","r"))==NULL){
printf("Cannotopenthisfile\n");
exit(0);
}即先檢查打開操作是否正確,如果有錯就在終端上輸出“Cannotopenthisfile”。
exit()函數的作用是關閉所有文件,終止正執行的程序。待程序員檢查出錯原因,修改后再運行。
(7)用以上方式可以打開文本文件或二進制文件,這是標準C的規定,用同一種緩沖文件系統來處理文本文件和二進制文件。但目前使用的有些C編譯系統可能不完全提供所有這些功能,例如有的只能用"r"、"w"、"a"方式,有的C版本不用"r+"、"w+"、"a+",而用"rw"、"wr"、"ar"等。請讀者注意所用系統的規定。
(8)在用文本文件向計算機輸入數據時,將回車換行符轉換為一個換行符,在輸出時把換行符轉換成回車和換行兩個字符。在用二進制文件時,不進行這種轉換,內存中的數據形式與輸出到外部文件中的數據形式完全一致,一一對應。10.2.2文件的關閉(fclose()函數)
在使用完一個文件后應該調用fclose()函數關閉文件。
fclose()函數的調用格式為fclose(文件指針)。例如“fclose(fp);”就表示把指針fp所指的文件關閉了,也就是斷開了打開文件時建立的數據流——fp與具體文件的聯系,即不能再通過fp對某個具體文件進行操作。如果在程序終止之前不關閉文件,將可能丟失緩沖區中最后一批未處理的數據,因為fclose()函數的調用不僅釋放文件指針,還刷新緩沖區。fclose()函數將緩沖區中可能遺留的未裝滿送走的數據輸入內存或輸出至磁盤文件,以確保數據不丟失。當然,程序結束時會自動關閉文件,但用完文件后及時關閉是一個好的編程習慣。
fclose()函數也返回一個值:0表示順利返回,非0表示關閉錯誤。10.3文件的讀/寫10.3.1fputc()函數和fgetc()函數
fputc()函數的調用形式為:
fputc(ch,fp);該函數的作用是將字符(ch的值)輸出到fp所指向的文件中。其中ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針,它是從fopen()函數得到的返回值。fputc()函數也帶回一個值,如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF。EOF是在stdio.h文件中定義的符號常量,值為-1。
fgetc()函數的調用形式為:
ch=fgetc(fp);該函數的作用是從指定文件讀入一個字符,該文件必須是以讀或讀/寫方式打開的。其中fp為文件型指針,指向所打開備讀的文件;ch為字符變量,接收fgetc()函數帶回的字符。如果在執行fgetc()讀字符時遇到文件結束符,函數則返回一個文件結束標志EOF,可以利用它來判斷是否讀完了文件中的數據。如想從一個磁盤文件按順序讀入字符并在屏幕上顯示出來,可編程為:
while((ch=fgetc(fp))!=EOF)
putchar(ch);注意,EOF不是可輸出字符,因此在屏幕上顯示不出來。由于字符的ASCII碼不可能出現-1,因此EOF定義為-1是合適的。當讀入的字符值等于-1(即EOF)時,表示讀入的已不是正常的字符而是文件結束符。但以上只適用于讀文本文件?,F在標準C已允許用緩沖文件系統處理二進制文件,讀入某一個字節中的二進制數據的值有可能是-1,而這又恰好是EOF的值。這就出現了讀入有用數據卻被處理為“文件結束”的情況,即終止符設置不恰當。為了解決這個問題,標準C提供了一個feof()函數來判斷文件是否真的結束。feof(fp)用來測試fp所指向的文件當前狀態是否為“文件結束”,如果是文件結束,函數feof(fp)的值為1(真),否則為0(假)。例如,順序讀入一個二進制文件中的數據的程序段如下:
while(!feof(fp))
{
c=fgetc(fp);
}當未遇文件結束時,feof(fp)的值為0,!feof(fp)為1,讀入一個字節的數據賦給變量c(接著可做其它處理),之后再求feof(fp)函數,循環工作直到文件結束,feof(fp)值變為1,!feof(fp)值為0,結束while循環。這種方法也適用于文本文件。在掌握了以上幾種函數以后,可以編制一些簡單的使用文件的程序,下面是一文件建立的例子。
例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輸出到顯示器上的字符串,與寫入文件的內容一樣,以資核對)程序運行之后,可以查看文件目錄,將多出一個名為fileex1.dat的數據文件,可用DOS命令將其內容打印出來:
typefileex1.dat↙Whatinsidethefile (由注3行循環寫入的)由上例可以看出,文件指針就是通向文件的數據流。當打開一個文件,執行fp=fopen(…)時,就將一個數據流與該文件聯系起來,其后對文件的操作都是對此文件指針fp的操作,即“脫離”具體文件,只通過對數據流的操作,完成對相應文件的操作。此后的程序直到執行相應的fclose(fp)函數之時,文件指針fp相當于該具體文件的全權代表。執行相應的fclose()函數時,關閉文件,就切斷了該文件與此數據流之間的聯系。10.3.2fgets()函數和fputs()函數
fgets()函數是從指定文件讀入一個字符串,其調用形式如下:
fgets(str,n,fp);該函數的功能是從fp指向的文件讀入n-1個字符,并把它們放到字符數組str(也可以是字符指針)中,如果在讀入n-1個字符結束之前遇到換行符或EOF,讀入即結束。字符串讀入在最后加一個′\0′字符,fgets()函數返回值為str的首地址。
fputs()函數是向指定的文件輸出一個字符串,其調用形式如下:
fputs(str,fp);該函數將字符串輸出到fp指向的文件。其中str可以是字符串常量、字符數組名或字符指針。若函數調用成功,返回0,否則返回非0值。例如:fputs(“China”,fp);即將字符串"China"輸出到fp指向的文件。這兩個函數類似以前介紹過的gets()和puts()函數,只是fgets()和fputs()函數以指定的文件作為讀/寫對象。10.3.3fprintf()函數和fscanf()函數
fprintf()函數、fscanf()函數與printf()和scanf()函數的作用類似,都是格式化讀/寫函數。前二者的讀/寫對象是磁盤文件,而后二者是終端設備。所以前二者函數調用參數中要多出一代表文件的文件指針。一般調用方式為:
fprintf(文件指針,控制字符串,參量表);
fscanf(文件指針,控制字符串,參量表);下例說明了這兩種函數的用法。例10.2
按格式鍵入字符型、整型、實型各一數,寫入文件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行即為格式化寫函數調用,將三數寫入文件;注3行是在寫操作完成之后關閉文件,若無此關閉操作,三數只能留在緩沖區中,而未真正寫到文件中。雖然其后接著要讀同一個文件,也仍然由fp指向,但此前的fp指向的是為寫打開的dform.dat,要想讀此文件,還必須再以讀的形式打開,再由fp指向。程序運行情況:
Inputchif:a22.2↙ (提示及輸入)
a└┘└┘└┘└┘22.2 (屏幕顯示)
dform.dat中的內容同屏顯。10.3.4fread()函數和fwrite()函數用fprintf()和fscanf()函數對磁盤文件讀/寫,使用方便,容易理解,但由于在輸入時要將ASClI碼轉換為二進制形式,在輸出時又要將二進制形式轉換成字符,花費時間比較多。再者,格式讀/寫只能面向數據項,對于結構體類型的變量則要一個一個成員地輸入/輸出,程序編寫比較繁瑣。因此,當文件內的數據以結構體類型組織或內存與磁盤頻繁交換數據時,最好不用fprintf()和fscanf()函數,而用成對讀/寫函數fread()和fwrite()。
fread()和fwrite()的一般調用形式為:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);其中:buffer是一個地址。對fread來說,它是讀入數據將要存放處的地址。對fwrite()來說,是要輸出數據的地址。
size是要讀/寫的一個數據塊的字節數。
count是要進行讀/寫數據塊的個數。
fp是文件指針,指向待讀或寫的文件。如果函數調用成功,則函數返回為count的值,即輸入或輸出數據項的完整個數;否則出錯。如果文件以二進制形式打開,則用fread()和fwrite()函數就可以讀/寫任何類型的信息。例如:
fread(f,4,2,fp);其中,f是一個實型數組名。一個實型變量占4個字節。這個函數從fp所指向的文件讀入2次(每次4個字節)數據,存儲到數組f中。下面以一文件建立為例說明一結構體變量的整體寫入。例10.3
建立一個有關工人工資的數據文件。
#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)
/*寫數據到文件中*/
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文件的定位前面已介紹過:文件中有一個位置指針指向下一個要讀的數據,稱為當前工作指針。每讀/寫完一個數據,該位置指針即自動向后移動一個數據的位置,指向了下一個要讀/寫的數據,這就是順序讀/寫。但實際處理中,常常要求隨機讀/寫或多次反復讀/寫,就要調用有關函數,強制位置指針指向其它位置。10.4.1rewind()函數
rewind()函數可以強制使當前工作指針指向文件的開頭。一般在要重新從頭讀/寫文件時使用。如下例,在讀了文件dfr.dat一遍送顯示器后,文件的位置指針已移到文件的最后,為了重新讀一遍再寫到文件dfw.dat中,必須先執行一次rewind()函數,才能正確讀出。例10.4
將已建好的文件dfr.dat的內容順序讀一遍送顯示器,再讀一遍復制到文件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);
/*寫數據到文件中*/
fclose(fp1);
fclose(fp2);
}若將例10.2產生的dform.dat拷貝為dfr.dat,則程序運行后,屏幕顯示為:
a,2,2.2所建立的dfw.dat文件的內容為a22.200000。10.4.2fseek()函數利用fseek()函數可以控制文件位置的指針進行隨機讀/寫。
fseek()函數的調用形式如下:
fseek(文件類型指針,位移量,起始點);起始點可按表10.2中規定的方式取值,既可以用標準C規定的常量名,也可以用對應的數字。位移量指從起始點向前移動的字節數。
fseek()函數一般用于二進制文件,因為文本文件要發生字符轉換,計算位置時容易發生混亂。下面是一個文件隨機讀/寫的例子。表10.2指針起始點的表示例10.5
將例10.3形成的職工數據文件中的第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);
/*從文件中讀出的數據存入結構體數組*/
printf(“%s%d%d\n”,worker[i].name,
worker[i].salary,worker[i].cost);
}
fclose(fp);
}若形成work.dat文件時的輸入數據為:
Li11100100↙
Li21200200↙
Li31300300↙
Li41400400↙
Li51500500↙
Li61600600↙則此程序的運行結果為:
Li11100100
Li31300300
Li5150050010.4.3ftell()函數
ftell()函數的作用是得到流式文件中位置指針的當前位置,用相對于文件開頭的位移量來表示。由于文件的位置指針經常移動,往往不易搞清其當前位置,用ftell()函數可以返回其當前位置,若返回-1L,表示函數調用出錯。例如:
i=ftell(fp);
if(i==-1L)printf("error\n");有關文件的處理函數還有很多,讀者可查看附錄二。初學者往往感到文件編程難,主要是對文件的概念比較陌生所致。其實,文件的編程并不是很難,只是在過去的數據處理程序的前后加上些有關文件的“套子”罷了,而這些有關文件的“套子”是相對程式化的。如果掌握了本書前面各章節的知識,只需記住有關文件的函數,理解文件的概念和處理步驟,再加上些出錯處理即可較容易地進行文件編程。10.5程序設計舉例
例10.6
若文件number.dat中存放了一組整數,試編程統計并輸出文件中正整數、零和負整數的個數。
#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. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2026學年寬城滿族自治縣三年級數學第一學期期末統考試題含解析
- 2025-2026學年甘肅省張掖市肅南裕固族自治縣數學三上期末考試模擬試題含解析
- 2025-2026學年噶爾縣三年級數學第一學期期末檢測試題含解析
- 2025-2026學年呈貢縣三上數學期末達標測試試題含解析
- 2024年遼寧省鞍山市立山區三年級數學第一學期期末質量跟蹤監視模擬試題含解析
- 2024年江蘇省南通市實小集團共同體三年級數學第一學期期末考試試題含解析
- 行政管理??普Z文應試試題及答案
- 2025年主管護師考試預測趨勢試題及答案
- 行政管理專業經典文獻試題及答案
- 曲藝與地方文化的融合試題及答案
- 2024年浙江湖州市城市投資發展集團招聘筆試參考題庫含答案解析
- 環境監測采樣安全培訓
- 水域救援小組器材裝備配備標準
- 小學數學-水中浸物問題-完整版題型訓練30題-帶答案
- 2022年消毒技術規范
- 數據標注與審核行業營銷策略方案
- 中國電信股份有限公司廣東公司4G四期規劃基站(廣州、清遠、韶關分冊)項目環境影響報告表
- 健康照明技術研究
- 年產3.0萬噸二甲醚裝置分離精餾工段的設計
- 驗房項目詳細表格
- 小學二年級下冊第19課-大象的耳朵教案(部編版)
評論
0/150
提交評論