在前面的程序設(shè)計(jì)中,我們介紹了輸入和輸出,即從標(biāo)準(zhǔn)輸入設(shè)備—鍵盤(pán)輸入,由標(biāo)準(zhǔn)
輸出設(shè)備—顯示器或打印機(jī)輸出。不僅如此,我們也常把磁盤(pán)作為信息載體,用于保存中
間結(jié)果或最終數(shù)據(jù)。在使用一些字處理工具時(shí),會(huì)利用打開(kāi)一個(gè)文件來(lái)將磁盤(pán)的信息輸入到
內(nèi)存,通過(guò)關(guān)閉一個(gè)文件來(lái)實(shí)現(xiàn)將內(nèi)存數(shù)據(jù)輸出到磁盤(pán)。這時(shí)的輸入和輸出是針對(duì)文件系統(tǒng),
故文件系統(tǒng)也是輸入和輸出的對(duì)象,談到輸入和輸出,自然也離不開(kāi)文件系統(tǒng)。
文件可以從不同的角度來(lái)分類(lèi):
1) 按文件所依附的介質(zhì)來(lái)分:有卡片文件、紙帶文件、磁帶文件、磁盤(pán)文件等。
2) 按文件內(nèi)容來(lái)分:有源文件、目標(biāo)文件、數(shù)據(jù)文件等。
3) 按文件中數(shù)據(jù)組織形式分:有字符文件和二進(jìn)制文件。
字符文件通常又稱(chēng)為A S C I I碼文件或正文文件,按字符存儲(chǔ),具有可讀性;而二進(jìn)制文件
是以二進(jìn)制存儲(chǔ),不具備可讀性,但從存儲(chǔ)空間的利用來(lái)看,實(shí)型數(shù)無(wú)論位數(shù)大小均占4位,
字符確需按位數(shù)來(lái)存放,這樣的話(huà),二進(jìn)制文件相對(duì)就節(jié)省了空間。
目前C語(yǔ)言使用的文件系統(tǒng)分為緩沖文件系統(tǒng)(標(biāo)準(zhǔn)I / O)和非緩沖文件系統(tǒng)(系統(tǒng)I / O)。
緩沖文件系統(tǒng)的特點(diǎn)是:在內(nèi)存開(kāi)辟一個(gè)“緩沖區(qū)”,為程序中的每一個(gè)文件使用,當(dāng)執(zhí)
行讀文件的操作時(shí),從磁盤(pán)文件將數(shù)據(jù)先讀入內(nèi)存“緩沖區(qū)”,裝滿(mǎn)后再?gòu)膬?nèi)存“緩沖區(qū)”依
此讀入接收的變量。執(zhí)行寫(xiě)文件的操作時(shí),先將數(shù)據(jù)寫(xiě)入內(nèi)存“緩沖區(qū)”,待內(nèi)存“緩沖區(qū)”
裝滿(mǎn)后再寫(xiě)入文件。由此可以看出,內(nèi)存“緩沖區(qū)”的大小,影響著實(shí)際操作外存的次數(shù),
內(nèi)存“緩沖區(qū)”越大,則操作外存的次數(shù)就少,執(zhí)行速度就快、效率高。一般來(lái)說(shuō),文件
“緩沖區(qū)”的大小隨機(jī)器而定。
8.1.1 文件的打開(kāi)與關(guān)閉
任何關(guān)于文件的操作都要先打開(kāi)文件,再對(duì)文件進(jìn)行讀寫(xiě),操作完畢后,要關(guān)閉文件。
1. 文件類(lèi)型指針
人們?cè)诓僮魑募r(shí),通常都關(guān)心文件的屬性,如文件的名字、文件的性質(zhì)、文件的當(dāng)前
狀態(tài)等。對(duì)緩沖文件系統(tǒng)來(lái)說(shuō),上述特性都是要仔細(xì)考慮的。ANSI C為每個(gè)被使用的文件在
內(nèi)存開(kāi)辟一塊用于存放上述信息的小區(qū),利用一個(gè)結(jié)構(gòu)體類(lèi)型的變量存放。該變量的結(jié)構(gòu)體
類(lèi)型由系統(tǒng)取名為F I L E,在頭文件s t d i o . h中定義如下:
typedef struct{
i n t _ f d ; / *文件號(hào)* /
i n t _ c l e f t ; / *緩沖區(qū)中的剩余字符* /
i n t _ m o d e ; / *文件的操作模式* /
c h a r * _ n e x t ; / *下一個(gè)字符的位置* /
char *_buff; / *文件緩沖區(qū)的位置* /
} FILE;
在操作文件以前,應(yīng)先定義文件變量指針:
FILE *fp1,fp2;
按照上面的定義,f p 1和f p 2均為指向結(jié)構(gòu)體類(lèi)型的指針變量,分別指向一個(gè)可操作的文件,
換句話(huà)說(shuō),一個(gè)文件有一個(gè)文件變量指針,今后對(duì)文件的訪(fǎng)問(wèn),會(huì)轉(zhuǎn)化為針對(duì)文件變量指針
的操作。
2. 文件的打開(kāi)
ANSI C 提供了打開(kāi)文件的函數(shù):
FILE *fopen(char *fname,char *mode)
函數(shù)原型在s t d i o . h文件中,f o p e n ( )打開(kāi)一個(gè)f n a m e指向的外部文件,返回與它相連接的流。
f n a m e是字符串,應(yīng)是一個(gè)合法的文件名,還可以指明文件路經(jīng)。對(duì)文件的操作模式由m o d e
決定,m o d e也是字符串,由表8 – 1給出m o d e的取值表。
如表8-1所示,文件的操作方式有文本文件和二進(jìn)制文件兩種,打開(kāi)文件的正確方法如下
例所示:
#include<stdio.h>
FILE *fp;
If((fp=fopen(“test.txt”,”w”))==NULL)
{/*創(chuàng)建一個(gè)只寫(xiě)的新文本文件*/
printf(“cannotopenfilen”);
exit(0);
}
這種方法能發(fā)現(xiàn)打開(kāi)文件時(shí)的錯(cuò)誤。在開(kāi)始寫(xiě)文件之前檢查諸如文件是否有寫(xiě)保護(hù),磁
盤(pán)是否已寫(xiě)滿(mǎn)等,因?yàn)楹瘮?shù)會(huì)返回一個(gè)空指針NULL,NULL值在stdio.h中定義為0。事實(shí)上打
開(kāi)文件是要向編譯系統(tǒng)說(shuō)明三個(gè)信息:①需要訪(fǎng)問(wèn)的外部文件是哪一個(gè)。②打開(kāi)文件后要執(zhí)
行讀或?qū)懠催x擇操作方式。③確定哪一個(gè)文件指針指向該文件。對(duì)打開(kāi)文件所選擇的操作方
式來(lái)說(shuō),一經(jīng)說(shuō)明不能改變,除非關(guān)閉文件后重新打開(kāi)。是只讀就不能對(duì)其寫(xiě)操作,對(duì)已存文件如以新文件方式打開(kāi),則信息必丟失。
3.文件的關(guān)閉
ANSIC提供了關(guān)閉文件的函數(shù):
intfclose(FILE*stream)
fclose()函數(shù)關(guān)閉與stream相連接的文件,并把它的緩沖區(qū)內(nèi)容全部寫(xiě)出。在fclose()函數(shù)
調(diào)用以后,流stream與此文件無(wú)關(guān),同時(shí)原自動(dòng)分配的緩沖區(qū)也失去定位。
fclose()函數(shù)關(guān)閉文件操作成功后,函數(shù)返回0;失敗則返回非零值。
[例8-1]打開(kāi)和關(guān)閉一個(gè)可讀可寫(xiě)的二進(jìn)制文件:
#include<stdio.h>
main ()
{
FILE *fp;
If((fp=fopen(“test.dat”,”rb”))==NULL)
{
printf(“cannotopenfilen”);
exit(0);
}
/*寫(xiě)入對(duì)文件執(zhí)行讀寫(xiě)的代碼
??*/
if(fclose(fp))printf(“filecloseerror!n”);
}
8.1.2文件的讀寫(xiě)
當(dāng)文件按指定的工作方式打開(kāi)以后,就可以執(zhí)行對(duì)文件的讀和寫(xiě)。下面按文件的性質(zhì)分
類(lèi)進(jìn)行操作。針對(duì)文本文件和二進(jìn)制文件的不同性質(zhì),對(duì)文本文件來(lái)說(shuō),可按字符讀寫(xiě)或按
字符串讀寫(xiě);對(duì)二進(jìn)制文件來(lái)說(shuō),可進(jìn)行成塊的讀寫(xiě)或格式化的讀寫(xiě)。
1.讀寫(xiě)字符
C提供fgetc和fputc函數(shù)對(duì)文本文件進(jìn)行字符的讀寫(xiě),其函數(shù)的原型存于stdio.h頭文件中,
格式為:
intfgetc(FILE*stream)
fgetc()函數(shù)從輸入流的當(dāng)前位置返回一個(gè)字符,并將文件指針指示器移到下一個(gè)字符處,
如果已到文件尾,函數(shù)返回EOF,此時(shí)表示本次操作結(jié)束,若讀寫(xiě)文件完成,則應(yīng)關(guān)閉文件。
intfputc(intch,FILE*stream)
fputc()函數(shù)完成將字符ch的值寫(xiě)入所指定的流文件的當(dāng)前位置處,并將文件指針后移
一位。fputc()函數(shù)的返回值是所寫(xiě)入字符的值,出錯(cuò)時(shí)返回EOF。
[例8-2]將存放于磁盤(pán)的指定文本文件按讀寫(xiě)字符方式逐個(gè)地從文件讀出,然后再將其
顯示到屏幕上。采用帶參數(shù)的main(),指定的磁盤(pán)文件名由命令行方式通過(guò)鍵盤(pán)給定。
#include<stdio.h>
main(argc,argv)
intargc;
char*argv[];
{
char ch;
FILE *fp;
int i;
if((fp=fopen(argv[1],”r”))==NULL)/*打開(kāi)一個(gè)由argv[1]所指的文件*/
{
printf(“notopen”);
exit(0);
}
while((ch=fgetc(fp))!=EOF)/*從文件讀一字符,顯示到屏幕*/
put char(ch);
fclose(fp);
}
程序是一帶參數(shù)的main()函數(shù),要求以命令行方式運(yùn)行,其參數(shù)argc是用于記錄輸入?yún)?shù)
的個(gè)數(shù),argv是指針數(shù)組,用于存放輸入?yún)?shù)的字符串,串的個(gè)數(shù)由argc描述。假設(shè)我們指定
讀取的文件名為L(zhǎng)8-2.c,并且列表文件內(nèi)容就是源程序。經(jīng)過(guò)編譯和連接生成可執(zhí)行的文件
L8-2.exe。運(yùn)行程序l8-2.exe,輸入的命令行方式為:
c:tc>l8-2L8-2.c
上述程序以命令行方式運(yùn)行,其輸入?yún)?shù)字符串有兩個(gè),即argv[0]=”c:tc>l8-2″、
argv[1]=”L8-2.c”,argc=2。故打開(kāi)的文件是L8-2.c。程序中對(duì)fgetc()函數(shù)的返回值不斷進(jìn)行
測(cè)試,若讀到文件尾部或讀文件出錯(cuò),都將返回C的整型常量EOF,其值為非零有效整數(shù)。程
序的運(yùn)行輸出為源程序本身:
c:tc>l8-2L8-2.c?
#include<stdio.h>
main(argc,argv)
int argc;
char *argv[];
{
char ch;
FILE *fp;
int i;
if((fp=fopen(argv[1],”r”))==NULL)/*打開(kāi)一個(gè)由argv[1]所指的文件*/
{
printf(“not open”);
exit(0);
}
while((ch=fgetc(fp))!=EOF)/*從文件讀一字符,顯示到屏幕*/
put char(ch);
fclose(fp);
}
[例8-3]從鍵盤(pán)輸入字符,存到磁盤(pán)文件test.txt中:
#include<stdio.h>
main()
{
FILE fp;/*定義文件變量指針*/
char ch;
if((fp=fopen(“test.txt”,”w”))==NULL)/*以只寫(xiě)方式打開(kāi)文件*/
{
printf(“cannotopenfile!n”);
exit(0);
}
while((ch=fgetchar())!=’n’)/*只要輸入字符非回車(chē)符*/
fputc(ch,fp)/*寫(xiě)入文件一個(gè)字符*/
fclose(fp);
}
程序通過(guò)從鍵盤(pán)輸入一以回車(chē)結(jié)束的字符串,寫(xiě)入指定的流文件test.txt,文件以文本只寫(xiě)方式打開(kāi),所以流文件具有可讀性,能支持各種字符處理工具訪(fǎng)問(wèn)。簡(jiǎn)單地說(shuō),我們可以通過(guò)DOS提供的type命令來(lái)列表顯示文件內(nèi)容。
2. 讀寫(xiě)字符串
C提供讀寫(xiě)字符串的函數(shù)原型在s t d i o . h頭文件中,其函數(shù)形式為:
Char *fgets(char *str,int num,FILE *stream)
fgets() 函數(shù)從流文件s t r e a m中讀取至多n u m – 1個(gè)字符,并把它們放入s t r指向的字符數(shù)組中。
讀取字符直到遇見(jiàn)回車(chē)符或E O F(文件結(jié)束符)為止,或讀入了所限定的字符數(shù)。
int fputs(char *str,FILE *stream)
f p u t s ( )函數(shù)將s t r指向的字符串寫(xiě)入流文件。操作成功時(shí),函數(shù)返回0值,失敗返回非零值。
[例8-4] 向磁盤(pán)寫(xiě)入字符串,并寫(xiě)入文本文件t e s t . t x t:
#include <stdio.h>
#include <string.h>
m a i n ( )
{
FILE *fp;
char str[128];
if ((fp=fopen(“test.txt”,”w”))==NUL/*L )打開(kāi)只寫(xiě)的文本文件*/
{
printf(“cannot open file!”);
e x i t ( 0 ) ;
}
w h i l e ( ( s t r l e n ( g e t s ( s t r ) ) ) ! = 0 )
{ /*若串長(zhǎng)度為零,則結(jié)束* /
f p u t s ( s t r , f p ) ; / *寫(xiě)入串* /
fputs(“n”,fp); /*寫(xiě)入回車(chē)符* /
}
fclose(fp); /*關(guān)文件* /
}
運(yùn)行該程序,從鍵盤(pán)輸入長(zhǎng)度不超過(guò)1 2 7個(gè)字符的字符串,寫(xiě)入文件。如串長(zhǎng)為0,即空串,程序結(jié)束。
這里所輸入的空串,實(shí)際為一單獨(dú)的回車(chē)符,其原因是g e t s函數(shù)判斷串的結(jié)束是以回車(chē)作
標(biāo)志的。
[例8-5] 從一個(gè)文本文件t e s t 1 . t x t中讀出字符串,再寫(xiě)入令一個(gè)文件t e s t 2 . t x t。
#include <stdio.h>
#include <string.h>
m a i n ( )
{
FILE *fp1,*fp2;
char str[128];
if ((fp1=fopen(“test1.txt”,”r”))==NULL)
{ / * 以只讀方式打開(kāi)文件1 * /
printf(“cannot open filen”);
e x i t ( 0 ) ;
}
if ((fp2=fopen(“test2.txt”,”w”))==NULL)
{ /*以只寫(xiě)方式打開(kāi)文件2 * /
printf(“cannot open filen”);
e x i t ( 0 ) ;
}
while ((strlen(fgets(str,128,fp1)))>0)
/ *從文件中讀回的字符串長(zhǎng)度大于0 */
{
fputs(str,fp2 ); / * 從文件1讀字符串并寫(xiě)入文件2 * /
p r i n t f ( ” % s ” , s t r ) ; / *在屏幕顯示* /
}
f c l o s e ( f p 1 ) ;
f c l o s e ( f p 2 ) ;
}
程序共操作兩個(gè)文件,需定義兩個(gè)文件變量指針,因此在操作文件以前,應(yīng)將兩個(gè)文件以需要的工作方式同時(shí)打開(kāi)(不分先后),讀寫(xiě)完成后,再關(guān)閉文件。設(shè)計(jì)過(guò)程是按寫(xiě)入文件的同時(shí)顯示在屏幕上,故程序運(yùn)行結(jié)束后,應(yīng)看到增加了與原文件相同的文本文件并顯示文
件內(nèi)容在屏幕上。
3. 格式化的讀寫(xiě)
前面的程序設(shè)計(jì)中,我們介紹過(guò)利用s c a n f ( )和p r i n t f ( )函數(shù)從鍵盤(pán)格式化輸入及在顯示器
上進(jìn)行格式化輸出。對(duì)文件的格式化讀寫(xiě)就是在上述函數(shù)的前面加一個(gè)字母f成為f s c a n f ( )和
f p r i n t f ( )。其函數(shù)調(diào)用方式:
int fscanf(FILE *stream,char *format,arg_list)
int fprintf(FILE *stream,char *format,arg_list)
其中,s t r e a m為流文件指針,其余兩個(gè)參數(shù)與s c a n f ( )和p r i n t f ( )用法完全相同。
[例8-6] 將一些格式化的數(shù)據(jù)寫(xiě)入文本文件,再?gòu)脑撐募幸愿袷交椒ㄗx出顯示到屏
幕上,其格式化數(shù)據(jù)是兩個(gè)學(xué)生記錄,包括姓名、學(xué)號(hào)、兩科成績(jī)。
#include <stdio.h>
m a i n ( )
{
FILE *fp;
int i;
struct stu{ / *定義結(jié)構(gòu)體類(lèi)型* /
char name[15];
char num[6];
float score[2];
} s t u d e n t ; / *說(shuō)明結(jié)構(gòu)體變量* /
if ((fp=fopen(“test1.txt”,”w”))==NULL)
{ / *以文本只寫(xiě)方式打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
printf(“input data:n”);
for( i=0;i<2;i++)
{
scanf(“%s %s %f %f”,student.name,student.num,&student.score[0],
&student.score[1]); / *從鍵盤(pán)輸入* /
fprintf(fp,”%s %s %7.2f %7.2fn”,student.name,student.num,
s t u d e n t . s c o r e [ 0 ] , s t u d e n t . s c o r e [ 1 ] ) ; / * 寫(xiě)入文件* /
}
f c l o s e ( f p ) ; / *關(guān)閉文件* /
if ((fp=fopen(“test.txt”,”r”))==NULL)
{ /*以文本只讀方式重新打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
printf(“output from file:n”);
while (fscanf(fp,”%s %s %f %fn”,student.name,student.num,
& s t u d e n t . s c o r e [ 0 ] , s t u d e n t . s c o r e [ 1 ] ) ! = E O F )
/ *從文件讀入* /
printf(“%s %s %7.2f %7.2fn”,student.name,student.num,student.score[0],student.score[1]); 顯/示* 到屏幕*/
fclose(fp); /*關(guān)閉文件*/
}
程序設(shè)計(jì)一個(gè)文件變量指針,兩次以不同方式打開(kāi)同一文件,寫(xiě)入和讀出格式化數(shù)據(jù),有一點(diǎn)很重要,那就是用什么格式寫(xiě)入文件,就一定用什么格式從文件讀,否則,讀出的數(shù)據(jù)與格式控制符不一致,就造成數(shù)據(jù)出錯(cuò)。上述程序運(yùn)行如下:
此程序所訪(fǎng)問(wèn)的文件也可以定為二進(jìn)制文件,若打開(kāi)文件的方式為:
if ((fp=fopen(“test1.txt”,”wb”))==NULL)
{ / * 以二進(jìn)制只寫(xiě)方式打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
其效果完全相同。
4. 成塊讀寫(xiě)
前面介紹的幾種讀寫(xiě)文件的方法,對(duì)其復(fù)雜的數(shù)據(jù)類(lèi)型無(wú)法以整體形式向文件寫(xiě)入或從文件讀出。C語(yǔ)言提供成塊的讀寫(xiě)方式來(lái)操作文件,使其數(shù)組或結(jié)構(gòu)體等類(lèi)型可以進(jìn)行一次性讀寫(xiě)。成塊讀寫(xiě)文件函數(shù)的調(diào)用形式為:
int fread(void *buf,int size,int count,FILE *stream)
int fwrite(void *buf,int size,int count,FILE *stream)
fread ()函數(shù)從stream 指向的流文件讀取count (字段數(shù))個(gè)字段,每個(gè)字段為s i z e (字段長(zhǎng)度)個(gè)字符長(zhǎng),并把它們放到b u f(緩沖區(qū))指向的字符數(shù)組中。
fread ()函數(shù)返回實(shí)際已讀取的字段數(shù)。若函數(shù)調(diào)用時(shí)要求讀取的字段數(shù)超過(guò)文件存放的字段數(shù),則出錯(cuò)或已到文件尾,實(shí)際在操作時(shí)應(yīng)注意檢測(cè)。
f w r i t e ( )函數(shù)從b u f (緩沖區(qū))指向的字符數(shù)組中,把c o u n t (字段數(shù))個(gè)字段寫(xiě)到s t r e a m所指向的流中,每個(gè)字段為s i z e個(gè)字符長(zhǎng),函數(shù)操作成功時(shí)返回所寫(xiě)字段數(shù)。
關(guān)于成塊的文件讀寫(xiě),在創(chuàng)建文件時(shí)只能以二進(jìn)制文件格式創(chuàng)建。
[例8-7] 向磁盤(pán)寫(xiě)入格式化數(shù)據(jù),再?gòu)脑撐募x出顯示到屏幕。
#include “stdio.h”
#include “stdlib.h”
m a i n ( )
{
FILE *fp1;
int i;
struct stu{ / *定義結(jié)構(gòu)體* /
char name[15];
char num[6];
float score[2];
} s t u d e n t ;
if ((fp1=fopen(“test.txt”,”wb”))==NULL)
{ /*以二進(jìn)制只寫(xiě)方式打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
printf(“input data:n”);
for( i=0;i<2;i++) {
scanf(“%s %s %f %f”,student.name,student.num,
& s t u d e n t . s c o r e [ 0 ] , & s t u d e n t . s c o r e [ 1 ] ) ; / * 輸入一記錄* /
fwrite(&student,sizeof(student),1,fp1);成 /塊*寫(xiě)入文件*/
}
f c l o s e ( f p 1 ) ;
if ((fp1=fopen(“test.txt”,”rb”))==NULL)
{ /*重新以二進(jìn)制只寫(xiě)打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
printf(“output from file:n”);
for (i=0;i<2;i++)
{
f r e a d ( & s t u d e n t , s i z e o f ( s t u d e n t ) , 1 , f p 1 ) ; / * 從文件成塊讀* /
printf(“%s %s %7.2f %7.2fn”,student.name,student.num,
s t u d e n t . s c o r e [ 0 ] , s t u d e n t . s c o r e [ 1 ] ) ; / * 顯示到屏幕* /
}
f c l o s e ( f p 1 ) ;
}
通常,對(duì)于輸入數(shù)據(jù)的格式較為復(fù)雜的話(huà),我們可采取將各種格式的數(shù)據(jù)當(dāng)做字符串輸入,然后將字符串轉(zhuǎn)換為所需的格式。C提供函數(shù):
int atoi(char *ptr)
float atof(char *ptr)
long int atol(char *ptr)
它們分別將字符串轉(zhuǎn)換為整型、實(shí)型和長(zhǎng)整型。使用時(shí)請(qǐng)將其包含的頭文件m a t h . h或s t d l i b . h寫(xiě)在程序的前面。
[例8-8] 將輸入的不同格式數(shù)據(jù)以字符串輸入,然后將其轉(zhuǎn)換進(jìn)行文件的成塊讀寫(xiě)。
#include <stdio.h>
#include <stdlib.h>
m a i n ( )
{
FILE *fp1;
char *temp;
int i;
struct stu{ / *定義結(jié)構(gòu)體類(lèi)型* /
char name[15]; / *姓名* /
char num[6]; / * 學(xué)號(hào)* /
float score[2]; / * 二科成績(jī)* /
} s t u d e n t ;
if ((fp1=fopen(“test.txt”,”wb”))==NULL) / * 打開(kāi)文件* /
{
printf(“cannot open file”);
e x i t ( 0 ) ;
}
for( i=0;i<2;i++) {
printf(“input name:”);
g e t s ( s t u d e n t . n a m e ) ; / *輸入姓名* /
printf(“input num:”);
g e t s ( s t u d e n t . n u m ) ; / * 輸入學(xué)號(hào)* /
printf(“input score1:”);
g e t s ( t e m p ) ; / *輸入成績(jī)* /
s t u d e n t . s c o r e [ 0 ] = a t o f ( t e m p ) ;
printf(“input score2:”);
g e t s ( t e m p ) ;
s t u d e n t . s c o r e [ 1 ] = a t o f ( t e m p ) ;
f w r i t e ( & s t u d e n t , s i z e o f ( s t u d e n t ) , 1 , f p 1 ) ; / *成塊寫(xiě)入到文件* /
}
f c l o s e ( f p 1 ) ;
if ((fp1=fopen(“test.txt”,”rb”))==NULL)
{
printf(“cannot open file”);
e x i t ( 0 ) ;
}
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
p r i n t f ( ” % – 1 5 s % – 7 s % – 7 s % – 7 s n ” , ” n a m e ” , ” n u m ” , ” s c o r e 1 ” , ” s c o r e 2 ” ) ;
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
for (i=0;i<2;i++)
{
f r e a d ( & s t u d e n t , s i z e o f ( s t u d e n t ) , 1 , f p 1 ) ;
p r i n t f ( ” % – 1 5 s % – 7 s % 7 . 2 f % 7 . 2 f n ” , s t u d e n t . n a m e , s t u d e n t . n u m ,
s t u d e n t . s c o r e [ 0 ] , s t u d e n t . s c o r e [ 1 ] ) ;
}
f c l o s e ( f p 1 ) ;
}
8.1.3 隨機(jī)讀寫(xiě)文件
隨機(jī)對(duì)文件的讀寫(xiě)是指在文件內(nèi)部任意對(duì)文件內(nèi)容進(jìn)行訪(fǎng)問(wèn),這也就需要對(duì)文件進(jìn)行詳
細(xì)的定位,只有定位準(zhǔn)確,才有可能對(duì)文件隨機(jī)訪(fǎng)問(wèn)。
C語(yǔ)言提供了用于文件定位的函數(shù),它的作用是使文件指針移動(dòng)到所需要的位置。
int fseek(FILE *fp,long d,int pos)
f p是文件指針,d是位移量,p o s是起始點(diǎn)。
P o s的取值為:
0 :文件開(kāi)始處
1 :文件的當(dāng)前位置
2 :文件的尾部
位移量d是l o n g型的數(shù)據(jù),可以為正或負(fù)值。表示從起始點(diǎn)向下或向上的指針移動(dòng)。函數(shù)
的返回值若操作成功為0,操作失敗為非零。
例如:f s e e k ( f p , 5 L , 0 );將文件指針從文件頭向下移動(dòng)5個(gè)字節(jié)。
f s e e k ( f p , – 1 0 L , 2 );將文件指針從當(dāng)前位置向上移動(dòng)1 0個(gè)字節(jié)。
rewind() 將文件指針移動(dòng)到文件頭。
ftell(FILE *fp) 返回文件指針的當(dāng)前位置。
[例8-9] 寫(xiě)入5個(gè)學(xué)生記錄,記錄內(nèi)容為學(xué)生姓名、學(xué)號(hào)、兩科成績(jī)。寫(xiě)入成功后,隨機(jī)
讀取第三條記錄,并用第二條記錄替換。
#include <stdio.h>
#include <stdlib.h>
#define n 5
m a i n ( )
{
FILE *fp1; / *定義文件指針* /
char *temp;
int i,j;
struct stu{ / * 定義學(xué)生記錄結(jié)構(gòu)* /
char name[15];
char num[6];
float score[2];
} s t u d e n t [ n ] ;
if ((fp1=fopen(“test.txt”,”wb”))==NULL) / *以二進(jìn)制只寫(xiě)方式打開(kāi)文件* /
{
printf(“cannot open file”);
e x i t ( 0 ) ;
}
for( i=0;i<n;i++)
{
printf(“input name:”); / *輸入姓名* /
g e t s ( s t u d e n t [ i ] . n a m e ) ;
printf(“input num:”);
g e t s ( s t u d e n t [ i ] . n u m ) ; / *輸入學(xué)號(hào)* /
printf(“input score1:”);
g e t s ( t e m p ) ; / *輸入一科成績(jī)* /
s t u d e n t [ i ] . s c o r e [ 0 ] = a t o f ( t e m p ) ;
printf(“input score2:”);
g e t s ( t e m p ) ; / * 輸入第二科成績(jī)* /
s t u d e n t [ i ] . s c o r e [ 1 ] = a t o f ( t e m p ) ;
fwrite(&student[i],sizeof(struct stu),1,fp1);成 塊/*寫(xiě)入*/
}
fclose(fp1); /*關(guān)閉* /
if ((fp1=fopen(“test.txt”,”rb+”))==NULL)
{ /*以可讀寫(xiě)方式打開(kāi)文件* /
printf(“cannot open file”);
e x i t ( 0 ) ;
}
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
p r i n t f ( ” % – 1 5 s % – 7 s % – 7 s % – 7 s n ” , ” n a m e ” , ” n u m ” , ” s c o r e 1 ” , ” s c o r e 2 ” ) ;
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
for (i=0;i<n;i++)
{ /*顯示全部文件內(nèi)容* /
fread(&student[i],sizeof(struct stu),1,fp1);
p r i n t f ( ” % – 1 5 s % – 7 s % 7 . 2 f % 7 . 2 f n ” , s t u d e n t [ i ] . n a m e , s t u d e n t [ i ] . n u m ,
s t u d e n t [ i ] . s c o r e [ 0 ] , s t u d e n t [ i ] . s c o r e [ 1 ] ) ;
}
/ *以下進(jìn)行文件的隨機(jī)讀寫(xiě)* /
fseek(fp1,3*sizeof(struct stu),0)/;* 定位文件指針指向第三條記錄*/
fwrite(&student[1],sizeof(struct stu),1,fp1);
/ * 在第三條記錄處寫(xiě)入第二條記錄* /
rewind(fp1); /*移動(dòng)文件指針到文件頭* /
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
p r i n t f ( ” % – 1 5 s % – 7 s % – 7 s % – 7 s n ” , ” n a m e ” , ” n u m ” , ” s c o r e 1 ” , ” s c o r e 2 ” ) ;
p r i n t f ( ” – – – – – – – – – – – – – – – – – – – – – n ” ) ;
for (i=0;i<n;i++)
{ /*重新輸出文件內(nèi)容* /
fread(&student[i],sizeof(struct stu),1,fp1);
p r i n t f ( ” % – 1 5 s % – 7 s % 7 . 2 f % 7 . 2 f n ” , s t u d e n t [ i ] . n a m e , s t u d e n t [ i ] . n u m ,
s t u d e n t [ i ] . s c o r e [ 0 ] , s t u d e n t [ i ] . s c o r e [ 1 ] ) ;
}
f c l o s e ( f p 1 ) ; / *關(guān)閉文件* /
}
程序的第二次輸出,即隨機(jī)訪(fǎng)問(wèn)后,文件中會(huì)有兩條相同的記錄。