版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第10章文件10.1文件概述
10.2文件的讀寫
10.3文件定位
習題
10.1文件概述
文件(file)是程序設計中一個重要的概念。所謂“文件”,一般指存儲在外部介質(zhì)上數(shù)據(jù)的集合。一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤)上的。操作系統(tǒng)是以文件為單位對數(shù)據(jù)進行管理的,也就是說,如果想找存在外部介質(zhì)上的數(shù)據(jù),必須先按文件名找到所指定的文件,然后再從該文件中讀取數(shù)據(jù)。要向外部介質(zhì)上存儲數(shù)據(jù),也必須先建立一個文件(以文件名標識),才能向它輸出數(shù)據(jù)。以前各章中所用到的輸入和輸出都是以終端為對象的,即從鍵盤輸入數(shù)據(jù),運行結(jié)果輸出到顯示屏上。從操作系統(tǒng)的角度看,每一個與主機相連的輸入/輸出設備都可看做是一個文件。例如,終端鍵盤是輸入文件,顯示屏和打印機是輸出文件。
在程序運行時,常常需要將一些數(shù)據(jù)(運行的最終結(jié)果或中間數(shù)據(jù))輸出到磁盤上存放起來,以后需要時再從磁盤中輸入到計算機內(nèi)存。這就要用到磁盤文件。
C語言把文件看做是一個字符(字節(jié))的序列,即由一個一個字符(字節(jié))的數(shù)據(jù)順序組成的。根據(jù)數(shù)據(jù)的組織形式,文件可分為ASCII文件和二進制文件。ASCII文件又稱文本(text)文件,它的每一個字節(jié)放一個ASCII代碼,代表一個字符。二進制文件是把內(nèi)存中的數(shù)據(jù)按其在內(nèi)存中的存儲形式原樣輸出到磁盤上存放。有一個整數(shù)10000,在內(nèi)存中占2個字節(jié),如果按ASCII碼形式輸出,則占5個字節(jié),而按二進制形式輸出,在磁盤上只占2個字節(jié),見圖10-1。用ASCII碼形式輸出與字符一一對應,一個字節(jié)代表一個字符,因而便于對字符進行逐個處理,也便于輸出字符,但一般占存儲空間較多,而且要花費轉(zhuǎn)換時間(二進制形式與ASCII碼間的轉(zhuǎn)換)。用二進制形式輸出數(shù)值,可以節(jié)省外存空間和轉(zhuǎn)換時間,但一個字節(jié)并不對應一個字符,不能直接輸出字符形式。一般中間結(jié)果數(shù)據(jù)需要暫時保存在外存上,以后又需要輸入到內(nèi)存的,常用二進制文件保存。圖10-1數(shù)據(jù)的存儲形式由前所述,一個C文件是一個字節(jié)流或二進制流。它把數(shù)據(jù)看作是一連串的字符(字節(jié)),而不考慮記錄的界限。換句話說,C語言中文件并不是由記錄(record)組成的(這是和Pascal或其他高級語言不同的)。在C語言中對文件的存取是以字符(字節(jié))為單位的。輸入/輸出的數(shù)據(jù)流的開始和結(jié)束僅受程序控制,而不受物理符號(如回車換行符)控制。也就是說,在輸出時不會自動增加回車換行符以作為記錄結(jié)束的標志,輸入時不以回車換行符作為記錄的間隔(事實上C文件并不由記錄構(gòu)成)。我們把這種文件稱為流式文件。C語言允許對文件存取一個字符,這就增加了處理的靈活性。在過去使用的C版本(如UNIX系統(tǒng)下使用的C)中有兩種對文件的處理方法:一種叫“緩沖文件系統(tǒng)”,另一種叫“非緩沖文件系統(tǒng)”。所謂緩沖文件系統(tǒng),是指系統(tǒng)自動地在內(nèi)存區(qū)為每一個正在使用的文件名開辟一個緩沖區(qū)。從內(nèi)存向磁盤輸出數(shù)據(jù)必須先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤去。如果從磁盤向內(nèi)存讀入數(shù)據(jù),則一次從磁盤文件將一批數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(給程序變量)。緩沖文件系統(tǒng)如圖10-2所示。緩沖區(qū)的大小由各個具體的C版本確定,一般為512字節(jié)。圖10-2緩沖文件系統(tǒng)示意圖所謂“非緩沖文件系統(tǒng)”是指系統(tǒng)不自動開辟確定大小的緩沖區(qū),而由程序為每個文件設定緩沖區(qū)。
在UNIX系統(tǒng)下,用緩沖文件系統(tǒng)來處理文本文件,用非緩沖文件系統(tǒng)處理二進制文件。用緩沖文件系統(tǒng)進行的輸入/輸出又稱為高級(或高層)磁盤輸入/輸出(高層I/O),用非緩沖文件系統(tǒng)進行的輸入/輸出又稱為低級(低層)輸入/輸出。ANSIC標準規(guī)定不采用非緩沖文件系統(tǒng),而只采用緩沖文件系統(tǒng),即用緩沖文件系統(tǒng)處理文本文件,也用它來處理二進制文件,也就是將緩沖文件系統(tǒng)擴充為可以處理二進制文件。在C語言中,沒有輸入/輸出語句,對文件的讀寫都是用庫函數(shù)來實現(xiàn)的。ANSI規(guī)定了標準輸入/輸出函數(shù),可用它們對文件進行讀寫。
本章只介紹ANSIC規(guī)定的文件系統(tǒng)以及對它的讀寫。
10.1.1文件和文件指針
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件指針”。每個被使用的文件都在內(nèi)存中開辟一個區(qū),用來存放文件的有關(guān)信息(如文件的名字、文件狀態(tài)及文件當前位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)定義的,取名為FILE。TurboC在stdio.h文件中有以下的文件類型聲明:typedef
struct
{
shortlevel; /*緩沖區(qū)“滿”或“空”的程度*/
unsignedflags; /*文件狀態(tài)標志*/
charfd;
/*文件描述符*/
unsignedcharhold; /*如無緩沖區(qū)則不讀取字符*/
shortbsize;
/*緩沖區(qū)的大小*/
unsignedchar*buffer; /*數(shù)據(jù)緩沖區(qū)的位置*/
unsignedar*curp; /*指針,當前的指向*/
unsignedistemp; /*臨時文件,指示器*/
shorttoken; /*用于有效性檢查*/
}FILE;有了結(jié)構(gòu)體FILE類型之后,就可以用它來定義若干個FILE類型的變量,以便存放若干個文件的信息。例如,可以定義以下FILE類型的數(shù)組:
FILE
f[5];
定義了一個結(jié)構(gòu)體數(shù)組f,它有5個元素,可以用來存放5個文件的信息。
可以定義文件型指針變量。如:
FILE*fp;
fp是一個指向FILE類型結(jié)構(gòu)體的指針變量。可以使fp指向某一個文件的結(jié)構(gòu)體變量,從而通過該結(jié)構(gòu)體變量中的文件信息能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它相關(guān)的文件。如果有n個文件,一般應設n個指針變量(指向FILE類型結(jié)構(gòu)體的指針變量),使它們分別指向n個文件(確切地說,是指向存放該文件信息的結(jié)構(gòu)體變量),以實現(xiàn)對文件的訪問。注意:
(1)由于文件類型FILE在頭文件stdio.h中定義,所以在使用FILE類型前必須先打開stdio.h文件。
(2)如果需要對某一個文件進行讀寫操作,則必須首先指定指向它的文件指針。只有通過文件指針,才能調(diào)用相應的文件。當程序需要同時處理多個文件時,則需要說明多個FILE型的指針變量,使它們分別指向多個不同的文件。10.1.2文件操作的一般過程
使用文件的一般步驟如下:打開文件→操作文件→關(guān)閉文件。
(1)打開文件:建立用戶程序與文件的聯(lián)系,系統(tǒng)為文件開辟文件緩沖區(qū)。
(2)操作文件:是指對文件的讀、寫、追加和定位操作。
①讀操作:從文件中讀出數(shù)據(jù),即將文件中的數(shù)據(jù)輸入到計算機內(nèi)存。
②寫操作:向文件中寫入數(shù)據(jù),即將計算機內(nèi)存中的數(shù)據(jù)輸出到文件。③追加操作:將新的數(shù)據(jù)寫到文件原有數(shù)據(jù)的后面。
④定位操作:移動文件讀寫位置指針。
(3)關(guān)閉文件:切斷文件與程序的聯(lián)系,將文件緩沖區(qū)的內(nèi)容寫入磁盤,并釋放文件緩沖區(qū)。10.1.3文件的打開與關(guān)閉
和其他高級語言一樣,對文件讀寫之前應該“打開”該文件,在使用結(jié)束之后應關(guān)閉該文件。
1.文件的打開(fopen函數(shù))
ANSIC規(guī)定了標準輸入/輸出函數(shù)庫,用fopen(
)函數(shù)來實現(xiàn)打開文件。
fopen函數(shù)的調(diào)用方式通常為:
FILE*fp;
fp=fopen(文件名,使用文件方式);
例如:
fp=fopen("a1","r");它表示要打開名字為a1的文件,使用文件方式為“讀入”(r代表read,即讀入)。fopen函數(shù)帶回指向a1文件的指針并賦給fp,這樣fp就和文件a1相聯(lián)系了,或者說,fp指向a1文件??梢钥闯觯诖蜷_一個文件時,通知給編譯系統(tǒng)以下3個信息:
①需要打開的文件名,也就是準備訪問的文件的名字。
②使用文件的方式(“讀”還是“寫”等)。
③讓哪一個指針變量指向被打開的文件。說明:
(1)用“r”方式打開的文件只能用于向計算機輸入而不能用作向該文件輸出數(shù)據(jù),而且該文件應該已經(jīng)存在。不能用“r”方式打開一個并不存在的文件(即輸入文件),否則出錯。
(2)用“w”方式打開的文件只能用于向該文件寫數(shù)據(jù)(即輸出文件),而不能用來向計算機輸入。如果原來不存在該文件,則在打開時新建立一個以指定的名字命名的文件。如果原來已存在一個以該文件名命名的文件,則在打開時將該文件刪去,然后重新建立一個新文件。
(3)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應該用“a”方式打開。但此時該文件必須已存在,否則將得到出錯信息。打開時,位置指針移到文件末尾。
(4)用“r+”、“w+”、“a+”方式打開的文件既可以用來輸入數(shù)據(jù),也可以用來輸出數(shù)據(jù)。用“r+”方式時,該文件應該已經(jīng)存在,以便能向計算機輸入數(shù)據(jù);用“w+”方式則新建立一個文件,先向此文件寫數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù);用“a+”方式打開的文件,原來的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。
(5)如果不能實現(xiàn)“打開”的任務,fopen函數(shù)將會帶回一個出錯信息。出錯的原因可能是用“r”方式打開一個并不存在的文件;磁盤出故障;磁盤已滿,無法建立新文件等。此時fopen函數(shù)將帶回一個空指針值NULL(NULL在stdio.h文件中已被定義為0)。常用下面的方法打開一個文件:if
((fp=fopen("file1","r"))==NULL)
{
printf("cannotopenthisfile\n");
exit(0);
}即先檢查打開的操作有否出錯,如果有錯就在終端上輸出“cannotopenthisfile”。exit函數(shù)的作用是關(guān)閉所有文件,終止正在調(diào)用的過程。待用戶檢查出錯誤,修改后再運行。
(6)用以上方式可以打開文本文件或二進制文件,這是ANSIC的規(guī)定,用同一種緩沖文件系統(tǒng)來處理文本文件和二進制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用“r”、“w”、“a”方式),有的C版本不用“r+”、“w+”、“a+”,而用“rw”、“wr”、“ar”等,請讀者注意所用系統(tǒng)的規(guī)定。
(7)在向計算機輸入文本文件時,將回車換行符轉(zhuǎn)換為一個換行符;在輸出時,把換行符轉(zhuǎn)換成為回車和換行兩個字符。在用二進制文件時,不進行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對應。
(8)在程序開始運行時,系統(tǒng)自動打開3個標準文件:標準輸入、標準輸出、標準出錯輸出。通常這3個文件都與終端相聯(lián)系。因此以前所用到的從終端輸入或輸出都不需要打開終端文件。系統(tǒng)自動定義了3個文件指針stdin、stdout和stderr,分別指向終端輸入、終端輸出和標準出錯輸出(也從終端輸出)。如果程序中指定要從stdin所指的文件輸入數(shù)據(jù),就是指從終端鍵盤輸入數(shù)據(jù)。
2.文件的關(guān)閉(fclose函數(shù))
在使用完一個文件后應該關(guān)閉它,以避免數(shù)據(jù)丟失?!瓣P(guān)閉”就是使文件指針變量不指向該文件,也就是文件指針變量與文件“脫鉤”,此后不能再通過該指針對原來與其相聯(lián)系的文件進行讀寫操作。(除非再次打開,使該指針變量重新指向該文件。)用fclose函數(shù)關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式為:
fclose(文件指針);
例如:
fclose(fp);前面曾把打開文件(用fopen函數(shù))時所帶回的指針賦給了fp,現(xiàn)在通過fp把該文件關(guān)閉。即fp不再指向該文件。
應該養(yǎng)成在程序終止之前關(guān)閉所有文件的習慣,如果不關(guān)閉文件將會引起數(shù)據(jù)丟失。如前所述,在向文件寫數(shù)據(jù)時,是先將數(shù)據(jù)輸?shù)骄彌_區(qū),待緩沖區(qū)充滿后才正式輸出給文件。如果當數(shù)據(jù)未充滿緩沖區(qū)而程序結(jié)束運行,就會將緩沖區(qū)中的數(shù)據(jù)丟失。用fclose函數(shù)關(guān)閉文件,可以避免這個問題,它先把緩沖區(qū)中的數(shù)據(jù)輸出到磁盤文件,然后才釋放文件指針變量。
fclose函數(shù)也帶回一個值,當順利地執(zhí)行了關(guān)閉操作,則返回值為0;否則返回EOF(-1)??梢杂胒error函數(shù)來進行測試。 10.2文?件?的?讀?寫
10.2.1fprintf和fscanf函數(shù)
fprintf函數(shù)、fscanf函數(shù)與printf函數(shù)、scanf函數(shù)作用相仿,都是格式化讀寫函數(shù)。只有一點不同:fprintf和fscanf函數(shù)的讀寫對象不是終端而是磁盤文件。它們的一般調(diào)用方
式為:
fprintf(文件指針,格式字符串,輸出表列);
fscanf(文件指針,格式字符串,輸入表列);例如:
fprintf(fp,"%d,%6.2f",i,t);
它的作用是將整型變量i和實型變量t的值按%d和%6.2f的格式輸出到fp指向的文件上。如果i=3,t=4.5,則輸出到磁盤文件上的是以下的字符串:
3,4.50
同樣,用以下fscanf函數(shù)可以從磁盤文件上讀入ASCII字符:
fscanf(fp,"%d,%f",&i,&t);磁盤文件上如果有以下字符:
3,4.5
則將磁盤文件中的數(shù)據(jù)3送給變量i,4.5送給變量t。
用fprintf和fscanf函數(shù)對磁盤文件讀寫,使用方便,容易理解,但由于在輸入時要將ASCII碼轉(zhuǎn)換為二進制形式,在輸出時又要將二進制形式轉(zhuǎn)換成字符,花費時間比較多,因此,?在內(nèi)存與磁盤頻繁交換數(shù)據(jù)的情況下,最好不用fprintf和fscanf函數(shù),而用fread和fwrite函數(shù)。10.2.2fputc和fgetc函數(shù)
1.fputc函數(shù)
fputc函數(shù)把一個字符寫到磁盤文件上去。其一般調(diào)用形式為:
fputc(ch,fp);
其中ch是要輸出的字符,它可以是一個字符常量,也可以是一個字符變量。fp是文件指針變量。fputc(ch,fp)函數(shù)的作用是將字符(ch的值)輸出到fp所指向的文件中去。
fputc函數(shù)也帶回一個值:如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個EOF(-1)。EOF是在stdio.h文件中定義的符號常量,其值為?-1。在第4章介紹過putchar函數(shù),其實putchar是從fputc函數(shù)派生出來的。putchar(c)是在stdio.h文件中用預處理命令#define定義的宏:
#define
putchar(c)
fputc(c,stdout)
前面已敘述,stdout是系統(tǒng)定義的文件指針變量,它與終端輸出相連。fputc(ch,stdout)的作用是將c的值輸出到終端。用宏putchar(c)比寫fputc(c,stdout)簡單一些。從用戶的角度,可以把putchar(c)看做函數(shù),而不必嚴格地稱它為宏。#include"stdio.h"
voidmain()
{
char*p="Thisisaexample.";
while(*p!='\0')
fputc(*p++,stdout);
}
2.fgetc函數(shù)
fgetc函數(shù)從指定文件讀入一個字符,該文件必須是以讀或讀寫方式打開的。
通常使用如下的形式調(diào)用fgetc()函數(shù):
ch=fgetc(fp);
其中,fp為文件型指針變量,ch為字符變量。正常情況下,fgetc()函數(shù)的返回值是從文件中讀出的一個字符。當打開文件并立即使用fgetc()讀文件時,fgetc()函數(shù)從文件開始位置讀取一個字符。每讀取一個字符后,文件的位置指針后移一個字符位置。若當前讀取的是文本文件,則當遇到文件結(jié)束標志時,fgetc()函數(shù)的返回值為EOF。在編寫程序時,經(jīng)常使用該返回值作為讀取文件字符的控制條件。例如使用fgetc()函數(shù)輸出程序e10-2.c的程序清單:#include"stdio.h"
main()
{
charch;
FILE*fp;
fp=fopen("e10-2.c","r");
while((ch=fgetc(fp))!=EOF)
putchar(ch);
fclose(fp);
}例10-1
把一個文本文件的內(nèi)容復制到另一個文本文件中。
/*源程序10-1*/
#include"stdio.h"
main()
{
charch,source[20],target[20];
FILE*fp_s,*fp_t;
printf("Enterthesourcefilename:");
scanf("%s",source);
printf("Enterthetargetfilename:");
scanf("%s",target);
if((fp_s=fopen(source,"r"))==NULL){
printf("cannotopensourcefile.\n");
exit(1);
}
if((fp_t=fopen(target,"w"))==NULL)
{
printf("cannotopentargetfile.\n");
exit(1);
}
while(!feof(fp_s))
fputc(fgetc(fp_s),fp_t);
fclose(fp_s);
fclose(fp_t);
}10.2.3fputs和fgets函數(shù)
fgets的作用是從指定文件讀入一個字符串,如:
fgets(str,n,fp);
其中,n為要求得到的字符,但只從fp指向的文件輸入n-1個字符,然后在最后加一個'\0'字符,因此得到的字符串共有n個字符。把它們放到字符數(shù)組str中。如果在讀完n-1個字符之前遇到換行符或EOF,讀入即結(jié)束。fgets函數(shù)返回值為str的首地址。
fputs函數(shù)的作用是向指定的文件輸出一個字符串。調(diào)用形式:
fputs(buffer,fp);
作用:將內(nèi)存buffer中的字符串寫到fp指向的文件中,buffer可以是一個字符串常量,也可以是字符串的首地址。
例10-2
將字符串?"VisualC++"?和?"Visualbasic"?依次存入文件text中,然后將第一個字符串讀出并顯示出來。/*源程序10-2*/
#include"stdio.h"
main()
{
FILE*fp;
charstring[20];
fp=fopen("text","w+");
fputs("VisualC++\n",fp);
fputs("Visualbasic\n",fp);
rewind(fp);
fgets(string,20,fp);
puts(string);
fclose(fp);
}
這兩個函數(shù)類似以前介紹過的gets和puts函數(shù),只是fgets和fputs函數(shù)以指定的文件作為讀寫對象。10.2.4fwrite和fread函數(shù)
getc和putc函數(shù)可以用來讀寫文件中的一個字符,但是常常要求一次讀入一組數(shù)據(jù)(例如,一個實數(shù)或一個結(jié)構(gòu)體變量的值)。ANSIC標準提出設置兩個函數(shù)(fread和fwrite),用來讀寫一個數(shù)據(jù)塊。
fwrite函數(shù)的功能是把內(nèi)存中的一些數(shù)據(jù)塊寫到指定的文件中。
一般調(diào)用形式:
fwrite(buffer,size,count,fp);其中:
①fp是接受數(shù)據(jù)的文件指針;
②buffer是數(shù)據(jù)塊的內(nèi)存首地址,通常是指針變量名、數(shù)組名等;
③size是一個數(shù)據(jù)塊的字節(jié)數(shù)(即數(shù)據(jù)塊的大小);
④count是執(zhí)行一次fwrite函數(shù)從內(nèi)存輸出到fp文件的數(shù)據(jù)塊數(shù)目。
例如,下面的語句將把內(nèi)存中結(jié)構(gòu)體數(shù)組stud的數(shù)據(jù)輸出到fp指向的文件中:
for(i=0;i<40;i++)
fwrite(&stud[i],sizeof(structstudent_type),1,fp);以下的語句,一次就把40個學生的數(shù)據(jù)輸出到文件中:
fwrite(stud,sizeof(structstudent_type),40,fp);
fread函數(shù)把指定文件中的一個數(shù)據(jù)塊讀到內(nèi)存中。
一般調(diào)用形式:
fread(buffer,size,count,fp);
其中:
①fp是讀取數(shù)據(jù)的文件指針;
②buffer是接受文件數(shù)據(jù)的內(nèi)存首地址,通常是指針變量名、數(shù)組名等;
③size是一個數(shù)據(jù)塊的字節(jié)數(shù)(即數(shù)據(jù)塊的大小);
④count是執(zhí)行一次fread()函數(shù)讀取的數(shù)據(jù)塊的數(shù)目。例如,設string.txt是一個文本文件,s是長度為50的char型一維數(shù)組,則執(zhí)行如下語句后,將讀出string.txt文件中的前10個字符,并依次存儲到數(shù)組s的前10個元素中:
FILE*fp;
fp=fopen("string.txt","r");
fread(s,2,5,fp);再如,設有如下定義:
structstudent_type
{
charname[10];
intnum;
intage;
}stud[40];其中,結(jié)構(gòu)體數(shù)組stud的每一個元素用來存放一個學生的有關(guān)數(shù)據(jù)。假設學生的數(shù)據(jù)已存放在磁盤文件中,且該文件已打開,并由fp指向,則可以用下面的語句把文件中前40個學生的數(shù)據(jù)輸入到結(jié)構(gòu)體數(shù)組stud中:
for(i=0;i<40;i++)
fread(&stud[i],sizeof(structstudent_type),1,fp);
例10-3
從鍵盤輸入4個學生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。/*源程序10-3*/
#include<stdio.h>
#defineSIZE4
structstudent_type
{
charname[10];
intnum;
intage;
charaddr[15];
}stud[SIZE];
voidsave(
)
{
FILEfp;
inti;
if((fp=fopen("stu-list","wb"))==NULL)
{
printf("cannotopenfile\n");
return;
}
for(i=0;i<SIZE;i++)
if(fwrite(&stud[i],sizeof(structstudent_type),1,fp)!=1)
printf("filewriteerror\n");
fclose(fp);}
main()
{
inti;
for(i=0;i<SIZE;i++)
scanf("%s%d%d%s",stud[i].name,&stud[i].num,
&stud[i].age,stud[i].addr);
save(
);
}在main函數(shù)中,從終端鍵盤輸入4個學生的數(shù)據(jù),然后調(diào)用save函數(shù),將這些數(shù)據(jù)輸出到以“stu_list”命名的磁盤文件中。fwrite函數(shù)的作用是將一個長度為29字節(jié)的數(shù)據(jù)塊送到stu_list文件中(一個student_type類型結(jié)構(gòu)體變量的長度為它的成員長度之和,即10+2+2+15=29)。運行情況如下:
輸入4個學生的姓名、學號、年齡和地址:
Zhang
1001
19 room-101
Fun 1002 20 room-102
Tan 1003 21 room-103
Ling 1004 21 room-104程序運行時,屏幕上并無任何輸出信息,只是將從鍵盤輸入的數(shù)據(jù)送到磁盤文件上。為了驗證在磁盤文件“stu_list”中是否已存在此數(shù)據(jù),可以用以下程序從“stu_list”文件中讀入數(shù)據(jù),然后在屏幕上輸出。/*源程序10-4*/
#include<stdio.h>
#defineSIZE4
structstudent-type
{
charname[10];
intnum;
intage;
charaddr[15];
}stud[SIZE];
main()
{
inti;
FILE*fp;
fp=fopen("stu_list","rb");
for(i=0;i<SIZE;i++)
{
fread(&stud[i],sizeof(structstudent_type),1,fp);
printf("%-10s%4d%4d%-5s\n",stud[i].name,&stud[i].
num,&stud[i].
Age,stud[i].addr);
fclose(fp);
}程序運行時不需從鍵盤輸入任何數(shù)據(jù)。屏幕上顯示出以下信息:
Zhang 1001 19 room-101
Fun 1002 20 room-102
Tan 1003 21 room-103
Ling 1004 21 room-104請注意輸入/輸出數(shù)據(jù)的狀況。從鍵盤輸入4個學生的數(shù)據(jù)是ASCII碼,也就是文本文件。在送到計算機內(nèi)存時,回車和換行符轉(zhuǎn)換成一個換行符。再從內(nèi)存以“wb”方式(二進制寫)輸出到“stu_list”文件,此時不發(fā)生字符轉(zhuǎn)換,按內(nèi)存中的存儲形式原樣輸出到磁盤文件上。在上面驗證程序中,又用fread函數(shù)從“stu_list”文件向內(nèi)存讀入數(shù)據(jù),注意此時用的是“rb”方式,即二進制方式,數(shù)據(jù)按原樣輸入,也不發(fā)生字符轉(zhuǎn)換。也就是這時候內(nèi)存中的數(shù)據(jù)恢復到“stu-list”輸出以前的情況。最后在驗證程序中,用printf函數(shù)輸出到屏幕。printf是格式輸出函數(shù),輸出ASCII碼,在屏幕上顯示字符。換行符又轉(zhuǎn)換為回車加換行符。如果企圖從“stu_list”文件中以“r”方式讀入數(shù)據(jù)就會出錯。
fread和fwrite函數(shù)一般用于二進制文件的輸入/輸出。因為它們是按數(shù)據(jù)塊的長度來處理輸入/輸出的,所以在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設想不同的情況。
例如,如果用
fread(&stud[i],sizeof(structstudent-type),1,stdin);
企圖從終端鍵盤輸入數(shù)據(jù),這在語法上并不存在錯誤,編譯能通過。如果用以下形式輸入數(shù)據(jù):
Zhang1001
10
room-101
…由于fread函數(shù)要求一次輸入29個字節(jié)(而不問這些字節(jié)的內(nèi)容),因此輸入數(shù)據(jù)中的空格也作為輸入數(shù)據(jù)而不作為數(shù)據(jù)間的分隔符,連空格也存儲到stud[i]中,顯然這是不對的。
這個題目要求的是從鍵盤輸入數(shù)據(jù),如果已有的數(shù)據(jù)已以二進制形式存儲在一個磁盤文件“stu-dat”中,要求從其中讀入數(shù)據(jù)并輸出到“stu-list”文件中,則可以編寫一個load函數(shù),從磁盤文件中讀二進制數(shù)據(jù)。/*源程序10-5*/
voidload(
)
{
FILE*fp;
inti;
if((fp=fopen("stu_dat","rb"))==NULL)
{
printf("cannotopeninfile\n");
return;
}
for(i=0;i<SIZE;i++)
if(fread(&stud[i],sizeof(structstudent_type),1,fp)!=1)
{
if(feof(fp)){fclose(fp);return;}
printf("filereaderror\n");
}
fclose(fp);
}將load函數(shù)加到本題原來的程序文件中,并將main函數(shù)改為:
main(
)
{
load(
);
save(
);
}
10.3文件定位
10.3.1rewind函數(shù)
rewind函數(shù)的作用是使位置指針重新返回文件的開頭。此函數(shù)沒有返回值。
例10-4
有一個磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復制到另一文件中。/*源程序10-6*/
#include<stdio.h>
main()
{
FILE*fp1,*fp2;
fp1=fopen("file1.c","r");
fp2=fopen("file2.c","w");
while(!feof(fp1))
putchar(getc(fp1));
rewind(fp1);
while(!feof(fp1))
putc(getc(fp1),fp2);
fclose(fp1);fclose(fp2);
}在第一次將文件的內(nèi)容顯示在屏幕以后,文件file1.c的位置指針已指到文件末尾,feof的值為非零(真)。執(zhí)行rewind函數(shù),使文件的位置指針重新定位于文件開頭,并使feof函數(shù)的值恢復為0(假)。
10.3.2fseek函數(shù)
功能:改變文件位置指針。
調(diào)用形式:
fseek(fp,offset,position);說明:
(1)?fp為文件型指針;
(2)文件位置指針的定位由參數(shù)offset和position共同確定。position規(guī)定指針定位時的基準位置;offset規(guī)定文件位置指針離開基準位置的偏移量,它的單位是字節(jié)。p
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 鄉(xiāng)鎮(zhèn)衛(wèi)生院醫(yī)生個人2022-2024-2025年度述職報告工作總結(jié)范文(14篇)
- 二零二五年礦泉水品牌戰(zhàn)略合作框架協(xié)議范本2篇
- 邯鄲2024年河北邯鄲廣平縣黨群系統(tǒng)事業(yè)單位招聘23人筆試歷年參考題庫附帶答案詳解
- 二零二五年度貨車轉(zhuǎn)讓及二手車鑒定評估與市場推廣服務協(xié)議3篇
- 二零二五年度環(huán)保技術(shù)開發(fā)與轉(zhuǎn)讓合同2篇
- 學校護校合同(2篇)
- 二零二五版中高端咖啡館所有權(quán)轉(zhuǎn)移及接手合同模板3篇
- 二零二五年環(huán)保型車輛贈與及綠色出行服務協(xié)議3篇
- 二零二五年度生物技術(shù)成果保密及轉(zhuǎn)讓合同3篇
- 二零二五年度環(huán)保項目委托運營協(xié)議3篇
- 深孔鉆床設備點檢表
- 四年級科學《運動與摩擦力》說課課件
- 訴訟費退費確認表
- 全球變暖視野下中國與墨西哥的能源現(xiàn)狀分析
- 新外研版八年級上冊英語全冊教案(教學設計)
- 2022年(高級)茶藝師職業(yè)資格考試參考題庫-下(多選、判斷題部分)
- 邊坡安全施工組織方案
- 【講座】新高考文言文命題特點及備考策略
- 熔煉系統(tǒng)冶金計算相關(guān)知識
- 《環(huán)境監(jiān)測》土壤環(huán)境質(zhì)量監(jiān)測方案設計
- 關(guān)于歐盟新版EMC標準EN55032的解析
評論
0/150
提交評論