文件打開之后,就可以對(duì)它進(jìn)行讀寫了。常用的讀寫函數(shù)如下所述。
13.4.1 fputc 函數(shù)和 fgetc 函數(shù)(putc 函數(shù)和 getc 函數(shù))
1. fputc 函數(shù)
把一個(gè)字符寫到磁盤文件上去。其一般調(diào)用形式為
fputc (ch,fp);
其中ch 是要輸出的字符,它可以是一個(gè)字符常量,也可以是一個(gè)字符變量.
fp 是文件指針變量。fputc (ch,fp) 函數(shù)的作用是將字符(ch的值)輸出到所指向的文件中去。fputc 函數(shù)也帶回一個(gè)值:如果輸出成功,則返回值就是輸出的字符;如果輸出失敗,則返回一個(gè)EOF(即—1)。EOF 是在 stdio.h 文件中定義的符號(hào)常量,值為—1。
在第4章介紹過(guò) putchar 函數(shù),其實(shí) putchar 是從 fputc 函數(shù)派生出來(lái)的。putchar(c) 是在 stdio.h 文件中用預(yù)處理命令 #define 定義的宏:
#define putchar(c) fputc(c,stdout)
前面已敘述,stdout 是系統(tǒng)定義的文件指針變量,它與終端輸出相聯(lián).
fputc(c,stdout)的作用是將 c 的值輸出到終端.用宏putchar(c)比寫fputc(c,stdout)
簡(jiǎn)單一些。從用戶的角度,可以把 putchar(c) 看作函數(shù)而不必嚴(yán)格地稱它為宏。
2.fgetc 函數(shù)
從指定的文件讀入一個(gè)字符,該文件必須是以讀或讀寫方式打開的。fgetc 函數(shù)的調(diào)用形式為: ch=fgetc(fp);
fp 為文件型指針變量,ch 為字符變量。fgetc 函數(shù)帶回一個(gè)字符,賦給 ch。
如果在執(zhí)行 fgetc 函數(shù)讀字符時(shí)遇到文件結(jié)束符,函數(shù)返回一個(gè)文件結(jié)束標(biāo)志EOF(即—1)。如果想從一個(gè)磁盤文件順序讀入字符并在屏幕上顯示出來(lái),可以用:
ch=fgetc(fp);
while(ch!=EOF)
{
putchar(ch);
ch=fgetc(fp);
}
注意:EOF 不是可輸出字符,因此不能在屏幕上顯示。由于字符的 ASCII 碼不可能出現(xiàn)—1,因此 EOF 定義為—1是合適的。當(dāng)讀入的字符值等于—1(即EOF)時(shí),表示讀入的已不是正常的字符而是文件結(jié)束符。但以上只適用于讀文本文件的情況。現(xiàn)在 ANSI C 已允許用緩沖文件系統(tǒng)處理二進(jìn)制文件,而讀入某一個(gè)字節(jié)中的二進(jìn)制數(shù)據(jù)的值有可能是—1,而這又恰好是EOF的值.
這就出現(xiàn)了需要讀入有用數(shù)據(jù)而卻被處理為“文件結(jié)束”的情況。為了解決這個(gè)問題,ANSI C 提供一個(gè) feof 函數(shù)來(lái)判斷文件是否真的結(jié)束。feof(fp)用來(lái)測(cè)試 fp 所指向的文件當(dāng)前狀態(tài)是否“文件結(jié)束”。如果是文件結(jié)束,函數(shù)feof(fp)的值為1(真);否則為0(假)。
如果想順序讀入一個(gè)二進(jìn)制文件中的數(shù)據(jù),可以用:
while(! feof(fp))
{
c=fgetc(fp);
……
}
當(dāng)未遇文件結(jié)束,feof(fp)的值為0,! feof(fp) 的值為1,讀入一個(gè)字節(jié)的數(shù)據(jù)賦給整型變量c,并接著對(duì)其進(jìn)行所需的處理。直到遇文件結(jié)束,feof(fp)值為1,! feof(fp) 值為0,不再執(zhí)行 while 循環(huán).
這種方法也適用于文本文件。
3. fputc 和 fgetc函數(shù)使用舉例
在掌握了以上幾種函數(shù)以后,可以編制一些簡(jiǎn)單的使用文件的程序。
例13 .1 從鍵盤輸入一些字符,逐個(gè)把它們送到磁盤上去,直到輸入一個(gè)“#”為止。程序如下: (本例有錯(cuò)誤)
#include "stdio.h"
#include "stdlib.h"
void main()
{
FILE * fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"W"))==NULL)
{
printf("cannot open file\n");
exit(0);
}
ch=getchar();
ch=getchar();
while(ch!='#')
{
fputc(ch,fp);
putchar(ch);
ch=getchar();
}
putchar(10);
fclose(fp);
}
運(yùn)行結(jié)果是:
輸入:file1.c
cannot open file
(不能打開文件)
文件名由鍵盤輸入,賦給字符數(shù)組 filename。 fopen 函數(shù)中的第一個(gè)參數(shù)“文件名” 可以直接寫成字符串常量形式(如file1.c),也可以用字符數(shù)組名,在字符數(shù)組中存放文件名(如本例所用的方法)。本例運(yùn)行時(shí),從鍵盤輸入磁盤文件名 “file1.c” ,然后輸入要寫入該磁盤文件的字符“ computer and c”, '#' 是表示輸入結(jié)束,程序?qū)?“ computer and c” 寫到以命名的磁盤文件中,同時(shí)在屏幕上顯示這些字符 ,以便核對(duì)。exit 是標(biāo)準(zhǔn) C 的庫(kù)函數(shù),作用是使程序終止,用此函數(shù)應(yīng)當(dāng)加入 stdlib 頭文件。
例13.2 將一個(gè)磁盤文件中的信息復(fù)制到另一個(gè)磁盤文件中。
(能運(yùn)行,不能復(fù)制 )
#include<stdlib.h>
#include<stdio.h>
void main()
{
FILE*in,*out;
char ch,infile[10],outfile[10];
printf("Enter the infile name:\n");
scanf("%s",infile);
printf("Enter the infile name:\n");
scanf("%s",outfile);
if((in=fopen(infile,"r"))==NULL)
{
printf("can not open infile\n");
exit(0);
}
if((out=fopen(outfile,"w"))==NULL)
{
printf("can not open outfile\n");
exit(0);
}
while(! feof(in)) fputc(fgetc(in),out);
fclose(in);
fclose(out);
}
運(yùn)行情況如下:
Enter the infile name:
file1.txt (輸入原有磁盤文件名)
Enter the infile name:
file2.txt (輸入新復(fù)制的磁盤文件名)
程序運(yùn)行結(jié)果是將 file1.txt 文件中的內(nèi)容復(fù)制到 file2.txt 中去。
以上程序是按文本文件方式處理的。也可以用此程序來(lái)復(fù)制一個(gè)二進(jìn)制文件,只需將兩個(gè) fopen 函數(shù)中的 r 和 w 分別改為 rb 和 wb 即可。
也可以在輸入命令行時(shí)把兩個(gè)文件名一起輸入。這時(shí)要用到 main 函數(shù)的參數(shù)。程序可改為:
#include<stdlib.h>
#include<stdio.h>
void main(int agc,char *argv[])
{
FILE * in,* out;
char ch;
if(argc !=3)
{
printf("You forgot to enter a filename\n");
exit(0);
}
if((in=fopen(argv[1],"r"))==NULL)
{
printf("cannot open infile\n");
exit(0);
}
if((out=fopen(argv[2],"w"))==NULL)
{
printf("cannot open infile\n");
exit(0);
}
while(! feof(in)) fputc(fgetc(in),out);
fclose(in);
fclose(out);
}
假若本程序的原文件名為 1.c 經(jīng)編譯連接后得到的可執(zhí)行文件名為 1.exe ,則在DOS命令工作方式下,可以輸入以下的命令行:C>1 file1.c file2.c 即在輸入可執(zhí)行文件名后,再輸入兩個(gè)參數(shù) file1.c 和 file2.c ,分別輸入到 argv[1]和 argv[2]中,argv[0]的內(nèi)容為a,argc 的值等于3(因?yàn)榇嗣钚泄灿?個(gè)參數(shù)) 。如果輸入的參數(shù)少于3個(gè),則程序會(huì)輸出:“You forgot to enter a filename”
(你忘了輸入一個(gè)文件名)。程序執(zhí)行結(jié)果是將 file1.c 中的信息復(fù)制到 file2.c 中。可以用以下命令驗(yàn)證:
C>type file1.c
computer and c
(這是 file1.c 文件中的信息)
C>type file2.c
computer and c
(這是 file2.c 文件中的信息。可見 file1.c已復(fù)制到 file2.c 中了)。
最后說(shuō)明一點(diǎn),為了書寫方便,系統(tǒng)把 fputc 和 fgetc 定義為宏名putc 和getc:
#define putc(ch,fp) fputc(ch,fp)
#define getc(fp) fgetc(fp)
這是在 stdio.h 中定義的。因此,用 putc 和 fputc 及用 getc 和 fgetc 是一樣的。一般可以把它們作為相同的函數(shù)來(lái)對(duì)待。
13.4.2 fead 函數(shù)和 fwrite 函數(shù)
用 getc 和 putc 函數(shù)可以用來(lái)讀寫文件中的一個(gè)字符。但是常常要求一次讀入一組數(shù)據(jù)(例如,一個(gè)實(shí)數(shù)或一個(gè)結(jié)構(gòu)體變量的值),ANSI C 標(biāo)準(zhǔn)提出設(shè)置兩個(gè)函數(shù)(fead 函數(shù)和 fwrite 函數(shù)),用來(lái)讀寫一個(gè)數(shù)據(jù)塊。它們的一般調(diào)用形式為:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
其中:buffer:是一個(gè)指針.對(duì) fread 來(lái)說(shuō),它是讀入數(shù)據(jù)的存放地址. 對(duì)fwrite 來(lái)說(shuō),
是要輸出數(shù)據(jù)的地址(以上指的是起始地址)。
size : 要讀寫的字節(jié)數(shù)。
count: 要進(jìn)行讀寫多少個(gè) size 字節(jié)的數(shù)據(jù)項(xiàng)。
fp: 文件型指針。
如果文件以二進(jìn)制形式打開,用 fead 和 fwrite 函數(shù)就可以讀寫任何類型的信息,例如: fead(f,4,2,fp); 其中 f 是一個(gè)實(shí)型數(shù)組名。一個(gè)實(shí)型變量占4個(gè)字節(jié)。這個(gè)函數(shù)從所指向的文件讀入2個(gè)4個(gè)字節(jié)的數(shù)據(jù),存儲(chǔ)到數(shù)組 f 中。
如果有一個(gè)如下的結(jié)構(gòu)體類型:
struct student_type
{
char name[10];
int num;
int age;
char addr[30];
}stud[40];
結(jié)構(gòu)體數(shù)組 stud 有40個(gè)元素,每一個(gè)元素用來(lái)存放一個(gè)學(xué)生的數(shù)據(jù)(包括姓名、學(xué)號(hào)、年齡、地址)。假設(shè)學(xué)生的數(shù)據(jù)已存放在磁盤文件中,可以用下面的 for 語(yǔ)句和 fread 函數(shù)讀入40個(gè)學(xué)生的數(shù)據(jù):
for(i=0;i<40;i++)
fread(&stud[i],sizeof(struct student_type),1,fp);
同樣,以下 for 語(yǔ)句和 fwrite 函數(shù)可以將內(nèi)存中的學(xué)生數(shù)據(jù)輸出到磁盤文件中去:
for(i=0;i<40;i++)
fwrite(&stud[i],sizeof(struct student_type),1,fp);
如果 fead 和 fwrite 調(diào)用成功,則函數(shù)返回值為 count 的值,既輸入或輸出數(shù)據(jù)項(xiàng)的完整個(gè)數(shù)。
下面寫出一個(gè)完整的程序。
例13.3 從鍵盤輸入4個(gè)學(xué)生的有關(guān)數(shù)據(jù),然后把它們轉(zhuǎn)存到磁盤文件上去。
#include "stdio.h"
#define SIZE 4
struct student_type
{char name[10];
int age;
int num;
char addr[15];
}stud[SIZE];
void save()
{
FILE * fp;
int i;
if((fp=fopen("stu_list","wb"))==NULL)
{
printf("cannot open file\n");
return;
}
for(i=0;i<SIZE;i++)
if(fwrite(&stud[i],sizeof(struct student_type),1,fp)!=1)
printf("file write error\n");
fclose(fp);
}
void main()
{
int i;
for(i=0;i<SIZE;i++)
scanf("%s%d%d%s",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
save();
}
在main 函數(shù)中,從終端鍵盤輸入4個(gè)學(xué)生的數(shù)據(jù),然后調(diào)用 save 函數(shù),將這些數(shù)據(jù)輸出到以 " stu_list "命名的磁盤文件中。fwrite 函數(shù)的作用是將一個(gè)
長(zhǎng)度為29字節(jié)數(shù)據(jù)塊送到 stu_list 文件中(一個(gè) student_type 類型結(jié)構(gòu)體變量的長(zhǎng)度為它的成員長(zhǎng)度之和,即10+2+2+15=29)。
運(yùn)行情況如下:
輸入4個(gè)學(xué)生的姓名、學(xué)號(hào)、年齡和地址:
Zhang 1001 18 room_101
Fun 1002 18 room_102
Tan 1003 18 room_103
Lin 1004 21 room_104
程序運(yùn)行時(shí),屏幕上并無(wú)輸出任何信息,只是將從鍵盤輸入的數(shù)據(jù)送到此盤文件上。為了驗(yàn)證在磁盤文件 “ stu_list ”中是否已存在此數(shù)據(jù),可以用以下程序從 stu_list 文件中讀入數(shù)據(jù),然后在屏幕上輸出。
#include "stdio.h"
#define SIZE 4
struct student_type
{
int age;
int num;
char addr[15];
char name[10];
}stud[SIZE];
void main()
{
int i;
FILE * fp;
fp=fopen("stu_list","rb");
for(i=0;i<SIZE;i++)
{
fread(&stud[i],sizeof(struct student_type),1,fp);
printf("%-10s %4d %4d %-15s\n",stud[i].name,&stud[i].age,&stud[i].num,stud[i].addr);
}
fclose(fp);
}
請(qǐng)注意:輸入輸出數(shù)據(jù)的狀況。從鍵盤輸入4個(gè)學(xué)生的數(shù)據(jù)是 ASCII 碼,也就是文本文件。在送到計(jì)算機(jī)內(nèi)存時(shí),回車和換行符轉(zhuǎn)換成一個(gè)換行符。再?gòu)膬?nèi)存以 “wb”方式(二進(jìn)制寫)輸出到 stu_list 文件,此時(shí)不發(fā)生字符轉(zhuǎn)換,按內(nèi)存中存儲(chǔ)形式原樣輸出到磁盤文件上。在上面驗(yàn)證程序中,又用“fread ”函數(shù)從 stu_list 文件向內(nèi)存讀入數(shù)據(jù),注意此時(shí)用的是“rb” 方式,即二進(jìn)制方式,數(shù)據(jù)按原樣輸入,也不發(fā)生字符轉(zhuǎn)換。也就是這時(shí)候內(nèi)存中的數(shù)據(jù)恢復(fù)到第一個(gè)程序向 “ stu_list ” 輸出以前的情況。最后在驗(yàn)證程序中,用printf 函數(shù)輸出到屏幕,printf 是格式輸出函數(shù),輸出 ASCII 碼,在屏幕上顯示字符。換行符又轉(zhuǎn)換為回車加換行符。
如果企圖從 “ stu_list ”文件中以 “r ”方式讀入數(shù)據(jù)就會(huì)出錯(cuò)。
fread 和 fwrire 函數(shù)一般用于二進(jìn)制文件的輸入輸出。因?yàn)樗鼈兪前磾?shù)據(jù)塊的長(zhǎng)度來(lái)處理輸入輸出的,在字符發(fā)生轉(zhuǎn)換的情況下很可能出現(xiàn)與原設(shè)想的情況不同。 例如,寫成:fread(&stud[i],sizeof(struct student_type),1,stdin); 企圖從終端鍵盤輸入數(shù)據(jù),這在語(yǔ)法上并不存在錯(cuò)誤,編譯能通過(guò)。如果用以下形式輸入數(shù)據(jù): Zhang 1001 18 room_101
……
由于 fread 函數(shù)要求一次輸入29個(gè)字節(jié)(而不問這些字節(jié)的內(nèi)容),因此輸入數(shù)據(jù)中的空格也作為輸入數(shù)據(jù)而不作為數(shù)據(jù)間的分隔符了。連空格也存儲(chǔ)到 stud[i] 中了,顯然是不對(duì)的。
這個(gè)題目要求的是從鍵盤輸入數(shù)據(jù),如果已有的數(shù)據(jù)已經(jīng)以二進(jìn)制形式存儲(chǔ)在一個(gè)磁盤文件 stu_dat 中,要求從其中讀入數(shù)據(jù)并輸出到 stu_list 文件中,可以編寫一個(gè) load 函數(shù),從磁盤文件中讀二進(jìn)制數(shù)據(jù)。
#include "stdio.h"
#define SIZE 4
struct student_type
{
int age;
int num;
char addr[15];
char name[10];
}stud[SIZE];
void load()
{
FILE * fp;
int i;
if((fp=fopen("stu_dat","rb"))==NULL)
{
printf("cannot open file\n");
return;
}
for(i=0;i<SIZE;i++)
if(fread(&stud[i],sizeof(struct student_type),1,fp)!=1)
{ if(feof(fp))
{ fclose(fp);
return;
}
printf("file write error\n");
}
fclose(fp);
}
main()
{
load();
save();
}
13.4.3 fprintf (從文件中輸出) 函數(shù)和 fscanf (從文件中讀入) 函數(shù)
fprintf 函數(shù)、fscanf 函數(shù) 與 printf 函數(shù)、scanf 函數(shù)作用相仿,都是格式讀寫函數(shù)。只有一點(diǎn)不同: fprintf 函數(shù)、fscanf 函數(shù)的讀寫對(duì)象不是終端而是磁盤文件。它們的一般調(diào)用方式為:
fprintf (文件指針,格式字符串,輸出表列);
fscanf (文件指針,格式字符串,輸入表列);
例如:
fprintf(fp,"%d,%6.2f",a,b);
它的作用是將整型變量 a 和實(shí)型變量 b 的值按 %d 和 %6.2f 的格式輸出到 fp 指向的文件上。如果 i=3,t=4.5 則輸出到磁盤文件上的是以下的字符串:
3, 4.50
同樣,用以下函數(shù)可以從磁盤文件上讀入 ASCII 字符:
fscanf(fp,"%d,%f",&a,&b);
磁盤文件上如果有這樣的字符:3, 4.5 即將磁盤文件中的數(shù)據(jù) 3送給變量 a,4.5 送給變量 b。
用 fprintf 和 fscanf 函數(shù)對(duì)磁盤文件讀寫,使用方便,容易理解,但由于在輸入時(shí)要將 ASCII 碼轉(zhuǎn)換為二進(jìn)制形式,在輸出時(shí)又要將二進(jìn)制形式轉(zhuǎn)換成字符,花費(fèi)時(shí)間比較多。因此,在內(nèi)存與磁盤頻繁交換數(shù)據(jù)的情況下,最好不用 fprintf 和 fscanf 函數(shù),而用 fread(從文件中讀) 和 fwrite(往文件中寫) 函數(shù)。
13.4.4 其它讀寫函數(shù)
1. putw 和 getw 函數(shù)
大多數(shù) C 編譯系統(tǒng)都提供另外兩個(gè)數(shù):putw 和 getw 函數(shù) ,用來(lái)對(duì)磁盤文件讀寫一個(gè)字(整數(shù))。例如: putw(10,fp); 它的作用是將整數(shù) 10 輸出到 fp指向的文件。而 i=getw(fp); 的作用是從磁盤文件讀一個(gè)整數(shù)到內(nèi)存,賦給整型變量 i。
如果所用的 C 編譯系統(tǒng)的庫(kù)函數(shù)中不包括 putw 和 getw 函數(shù),可以自己定義這兩個(gè)函數(shù)。putw 函數(shù)如下:
putw(int i,FILE * fp)
{
char * s; 圖1: i
s=&i; 00000000 00001010
putc(s[0],fp); s[0] s[1]
putw(s[1],fp);
return(i);
}
當(dāng)調(diào)用 putw 函數(shù)時(shí),如果用 putw(10,fp); 語(yǔ)句, 形參 i 得到實(shí)參傳來(lái)的值 10, 在 putw 函數(shù)中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個(gè)字節(jié),s+1 指向 i 的第 2 個(gè)字節(jié)。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對(duì)應(yīng)的第 1 個(gè)字節(jié)和第 2 個(gè)字節(jié)。順序輸出s[0]、s[1]就相當(dāng)于輸出了 i 的兩個(gè)字節(jié)中的內(nèi)容,見圖1.
getw 函數(shù)如下:
getw(FILE * fp)
{
char * s;
int i;
s=char * &i; /*使 s 指向 i 的起始地址 */
s[0]=getc(fp);
s[1]=getc(fp);
return(i);
}
putw 和 getw 函數(shù)并不是 ANSI C 標(biāo)準(zhǔn)定義的函數(shù)。許多 C 編譯系統(tǒng)都提供這兩個(gè),但有的不以 putw 和 getw 命名此兩函數(shù),而用其它函數(shù)名,用時(shí)要注意。
2. 讀寫其它類型數(shù)據(jù)
如果用 ANSI C 提供的 fread 和 fwrite函數(shù),讀寫任何類型數(shù)據(jù)都是十分方便的。如果所用的系統(tǒng)不提供這兩個(gè)函數(shù),用戶只好自己定義所需函數(shù)。例如,可以定義一個(gè)向磁盤文件寫一個(gè)實(shí)數(shù)(用二進(jìn)制方式)函數(shù) putfloat:
putfloat(float num,FILE * fp)
{
char * s;
int count;
s=(char *) #
for(count=0;count<4,count++)
putc(s[count],fp);
}
同樣可以編寫出讀寫任何類型數(shù)據(jù)的函數(shù)。
3. fgets 函數(shù)和 fputs 函數(shù)
fgets 函數(shù)的作用是從指定文件讀入一個(gè)字符串。例如:fgets (str,a,fp); a 為要求得到的字符,但只從 fp指向的文件輸入 a-1 個(gè)字符,然后在最后加一個(gè)‘ \0 ’字符,因此得到的字符串共有 a 個(gè)字符,把它們放到字符數(shù)組 str 中.如果
在讀完 a-1個(gè)字符之前遇到換行符或 EOF ,讀入即結(jié)束。 fgets 函數(shù)返回值為 str 的首地址。
fputs 函數(shù)的作用是從指定文件輸出一個(gè)字符串。例如:fputs("Wolong",fp);
把字符串 “ Wolong ” 輸出到 fp 指向的文件。fputs 函數(shù)中第一個(gè)參數(shù)可以是字符串常量、字符數(shù)組名或字符指針。 字符串末尾的‘ \0 ’ 不輸出。若輸出成功,函數(shù)值為 0;失敗時(shí),為 EOF 。
這兩個(gè)函數(shù)類似以前介紹過(guò)的 gets 和 puts 函數(shù), 只是 fgets 和 fputs 函數(shù)以指定的文件為讀寫對(duì)象。
fgets(從文件中獲取字符串)
fputs(往文件中寫字符串)
如果所用的 C 編譯系統(tǒng)的庫(kù)函數(shù)中不包括 putw 和 getw 函數(shù),可以自己定義這兩個(gè)函數(shù)。putw 函數(shù)如下:
putw(int i,FILE * fp)
{
char * s; 圖1: i
s=&i; 00000000 00001010
putc(s[0],fp); s[0] s[1]
putw(s[1],fp);
return(i);
}
當(dāng)調(diào)用 putw 函數(shù)時(shí),如果用 putw(10,fp); 語(yǔ)句, 形參 i 得到實(shí)參傳來(lái)的值 10, 在 putw 函數(shù)中將 i 的地址賦予指針變量 s ,而 s 是指向字符變量的指針變量,因此 s 指向 i 的第 1 個(gè)字節(jié),s+1 指向 i 的第 2 個(gè)字節(jié)。由于 * (s+0)就是 s[0],* (s+1)就是 s[1],因此,s[0]、s[1]分別對(duì)應(yīng)的第 1 個(gè)字節(jié)和第 2 個(gè)字節(jié)。順序輸出s[0]、s[1]就相當(dāng)于輸出了 i 的兩個(gè)字節(jié)中的內(nèi)容,見圖1.
getw 函數(shù)如下:
getw(FILE * fp)
{
char * s;
int i;
s=char * &i; /*使 s 指向 i 的起始地址 */
s[0]=getc(fp);
s[1]=getc(fp);
return(i);
}
如果用 ANSI C 提供的 fread 和 fwrite函數(shù),讀寫任何類型數(shù)據(jù)都是十分方便的。如果所用的系統(tǒng)不提供這兩個(gè)函數(shù),用戶只好自己定義所需函數(shù)。例如,可以定義一個(gè)向磁盤文件寫一個(gè)實(shí)數(shù)(用二進(jìn)制方式)函數(shù) putfloat:
putfloat(float num,FILE * fp)
{
char * s;
int count;
s=(char *) #
for(count=0;count<4,count++)
putc(s[count],fp);
}
同樣可以編寫出讀寫任何類型數(shù)據(jù)的函數(shù)。
例13.1從鍵盤輸入一些字符,逐個(gè)把它們送到磁盤上,直到輸入一個(gè)"#"為止.程序如下:
#include<stdlib.h>
#include<stdio.h>
void main()
{
FILE*fp;
char ch,filename[10];
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL)
{
printf("can not open file\n");
exit(0);/*終止程序*/
}
ch=getchar();/*接收輸入的一個(gè)字符*/
ch=getchar();/*這一句可以省略.*/
while(ch!='#')
{
fputc(ch,fp);putchar(ch);
ch=getchar();
}
putchar(10);/*向屏幕輸出一個(gè)換行符*/
fclose(fp);
}
運(yùn)行后的結(jié)果:輸入:is a c# 輸出 a c
13.5 文件的定位
文件中有一個(gè)位置指針,指向當(dāng)前讀寫的位置。如果順序讀寫一個(gè)文件,每次讀寫一個(gè)字符,則讀寫完一個(gè)字符后,該位置指針自動(dòng)移動(dòng)指向下一個(gè)字符位置。如果想改變這樣的規(guī)律,強(qiáng)制使位置指針指向其它指定的位置,可以用后面介紹的有關(guān)函數(shù)。
13.5.1 rewind 函數(shù)
rewind 函數(shù)的作用是使位置指針重新返回文件的開頭,此函數(shù)沒有返回值。
例13.4 有一個(gè)磁盤文件,第一次將它的內(nèi)容顯示在屏幕上,第二次把它復(fù)制到另一文件上。
#include "stdio.h"
void main()
{
FILE * fp1,* fp2;
fp1=fopen("file1.txt","r");
fp2=fopen("file2.txt","w");
while(! feof(fp1))
putchar(getc(fp1));
rewind(fp1);
while(! feof(fp1))
putc(getc(fp1),fp2);
fclose(fp1);
fclose(fp2);
}
(先在某一個(gè)位置上新建立一個(gè)文本文件,命名為file1.txt然后運(yùn)行本程序(在vc編譯系統(tǒng)運(yùn)行過(guò)))如:“ file1.txt ”里面的內(nèi)容是:
Nu11 pointer assignment
(無(wú)效的) ( 指示器)(分配、任務(wù)、作業(yè))
運(yùn)行后的結(jié)果是:
在第一次將內(nèi)容顯示在屏幕上,file1.txt 的位置指針已指到文件末尾,feof 的值為零(真)。執(zhí)行 rewind 函數(shù) ,使文件的位置指針重新定位于文件開頭,并使 feof 函數(shù)的值恢復(fù)為0(假)。
fopen (打開文件) fclose(文件關(guān)閉) rewind(重新) putchar(寫一個(gè)字符的函數(shù))feof=end of file (文件末尾) putc (輸出字符)