文件是一種信息存儲(chǔ)的方式,程序設(shè)計(jì)不可避免要進(jìn)行各種文件操作,一個(gè)程序在運(yùn)行過(guò)程中通常要從文件中讀取信息,在文件中存儲(chǔ)計(jì)算結(jié)果。
1 C文件的概念
在C語(yǔ)言中實(shí)現(xiàn)文件操作一般采取兩種途徑。
第一種:調(diào)用C語(yǔ)言中有關(guān)文件處理的標(biāo)準(zhǔn)庫(kù)函數(shù)。
第二種:直接調(diào)用操作系統(tǒng)提供的有關(guān)方面的功能。
所謂"文件"一般指存儲(chǔ)在外部介質(zhì)上數(shù)據(jù)的集合。
2 文件類(lèi)型指針
Turbo C在stdio.h文件中有以下的文件類(lèi)型聲明:
typedef struct
{ short level; /*緩沖區(qū)"滿"或"空"的程度*/
unsigned flags; /*文件狀態(tài)標(biāo)志*/
char fd; /*文件描述符*/
unsigned char hold; /*如無(wú)緩沖區(qū)不讀取字符*/
short bsize; /*級(jí)沖區(qū)的大小*/
unsigned char *baffer; /*數(shù)據(jù)緩沖區(qū)的位置*/
unsigned ar *curp; /*指針,當(dāng)前的指向*/
unsigned istemp; /*臨時(shí)文件,指示器*/
short token; /*用于有效性檢查*/
}FILE;
3 文件的打開(kāi)和關(guān)閉
和其他高級(jí)語(yǔ)言一樣,對(duì)文件讀寫(xiě)之前應(yīng)該"打開(kāi)"該文件,在使用結(jié)束之后應(yīng)關(guān)閉該文件。
一、文件的打開(kāi)(fopen函數(shù))
ANSI C規(guī)定了標(biāo)準(zhǔn)輸入輸出函數(shù)庫(kù),用fopen()函數(shù)來(lái)實(shí)現(xiàn)打開(kāi)文件。fopen函數(shù)的調(diào)用方式通常為:
FILE *fp;
fp=fopen(文件名,使用文件方式);
例如:fp=fopen("al",nr");
它表示要打開(kāi)名字為al的文件,使用文件方式為"讀入"(r代表read,即讀入),fopen函數(shù)帶回指向al文件的指針并賦給fp,這樣fp就和文件al相聯(lián)系了,或者說(shuō),fp指向al文件。可以看出,在打開(kāi)一個(gè)文件時(shí),通知給編譯系統(tǒng)以下3個(gè)信息:①需要打開(kāi)的文件名,也就是準(zhǔn)備訪問(wèn)的文件的名字。②使用文件的方式("讀"還是"寫(xiě)"等)。③讓哪一個(gè)指針變量指向被打開(kāi)的文件。
說(shuō)明:
(1)用"r"方式打開(kāi)的文件只能用于向計(jì)算機(jī)輸人而不能用作向該文件輸出數(shù)據(jù),而且該文件應(yīng)該已經(jīng)存在,不能用"r"方式打開(kāi)一個(gè)并不存在的文件(即輸入文件),否則出錯(cuò)。
(2)用"w"方式打開(kāi)的文件只能用于向該文件寫(xiě)數(shù)據(jù)(即輸出文件),而不能用來(lái)向計(jì)算機(jī)輸入。如果原來(lái)不存在該文件,則在打開(kāi)時(shí)新建立一個(gè)以指定的名字命名的文件。如果原來(lái)已存在一個(gè)以該文件名命名的文件,則在打開(kāi)時(shí)將該文件刪去,然后重新建立一個(gè)新文件。
(3)如果希望向文件末尾添加新的數(shù)據(jù)(不希望刪除原有數(shù)據(jù)),則應(yīng)該用"a"方式打開(kāi)。但此時(shí)該文件必須已存在,否則將得到出錯(cuò)信息。打開(kāi)時(shí),位置指針移到文件末尾。
(4)用"r+"、"w+"、"a+"方式打開(kāi)的文件既可以用來(lái)輸人數(shù)據(jù),也可以用來(lái)輸出數(shù)據(jù)。用"r+"方式時(shí)該文件應(yīng)該已經(jīng)存在,以便能向計(jì)算機(jī)輸入數(shù)據(jù)。用"w+"方式則新建立一個(gè)文件,先向此文件寫(xiě)數(shù)據(jù),然后可以讀此文件中的數(shù)據(jù)。用"a+"方式打開(kāi)的文件,原來(lái)的文件不被刪去,位置指針移到文件末尾,可以添加,也可以讀。
(5)如果不能實(shí)現(xiàn)"打開(kāi)"的任務(wù),fopen函數(shù)將會(huì)帶回一個(gè)出錯(cuò)信息。出錯(cuò)的原因可能是用"r"方式打開(kāi)一個(gè)并不存在的文件;磁盤(pán)出故障;磁盤(pán)己滿無(wú)法建立新文件等。此時(shí)fopen函數(shù)將帶回一個(gè)空指針值NULL(NULL在stdio.h文件中已被定義為0)。
(6)用以上方式可以打開(kāi)文本文件或二進(jìn)制文件,這是ANSI C的規(guī)定,用同一種緩沖文件系統(tǒng)來(lái)處理文本文件和二進(jìn)制文件。但目前使用的有些C編譯系統(tǒng)可能不完全提供所有這些功能(例如有的只能用"r"、"w"、"a"方式),有的C版本不用"r+"、"w+"、"a+",而用"rw"、"wr"、"ar"等,請(qǐng)讀者注意所用系統(tǒng)的規(guī)定。
(7)在向計(jì)算機(jī)輸人文本文件時(shí),將回車(chē)換行符轉(zhuǎn)換為一個(gè)換行符,在輸出時(shí)把換行符轉(zhuǎn)換成為回車(chē)和換行兩個(gè)字符。在用二進(jìn)制文件時(shí),不進(jìn)行這種轉(zhuǎn)換,在內(nèi)存中的數(shù)據(jù)形式與輸出到外部文件中的數(shù)據(jù)形式完全一致,一一對(duì)應(yīng)。
(8)在程序開(kāi)始運(yùn)行時(shí),系統(tǒng)自動(dòng)打開(kāi)3個(gè)標(biāo)準(zhǔn)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)出錯(cuò)輸出。
二、文件的關(guān)閉(fclose 函數(shù))
fclose(文件指針);
例如:fclose(fp);
4 文件的讀寫(xiě)
一、fputc函數(shù)和fgetc函數(shù)(putc函數(shù)和getc函數(shù))
1. fputc函數(shù)
把一個(gè)字符寫(xiě)到磁盤(pán)文件上去。其一般調(diào)用形式為:
fputc(ch,fp);
2. fgetc函數(shù)
從指定的文件讀入一個(gè)字符,該文件必須是以讀或讀寫(xiě)方式打開(kāi)的。fgetc函數(shù)的調(diào)用形式為:
ch=fgetc(fp);
如果想從一個(gè)磁盤(pán)文件順序讀入字符并在屏幕上顯示出來(lái),可以:
ch=fgetc(fp);
while(ch!=EOF)
{ putchar(ch);
ch=fgetc(fp);
}
如果想順序讀入一個(gè)二進(jìn)制文件中的數(shù)據(jù),可以用:
while(! feof(fp))
{c=fgetc(fp);
}
3. fputc和fgetc函數(shù)使用舉例
例11.1 從鍵盤(pán)輸入一些字符,逐個(gè)把它們送到磁盤(pán)上去,直到輸入一個(gè)"#"為止。
#include <stdio.h>
main()
{ file*fp;
char ch,filename[l0];
scanf("%s",filename);
if((fp=fopen(filename,"w"))==NULL)
{printf("cannot open file\n");
exit(0);
ch=getchar();
while(ch!='#')
{
fputc(ch,fp);putchar(ch);
ch=getchar();
}
fclose(fp);
}
運(yùn)行情況如下:
file1.c (輸入磁盤(pán)文件名)
computer and c# (輸入一個(gè)字符串)
computer and c (輸出一個(gè)字符串)
可以用DOS命令將file1.c文件中的內(nèi)容打印出來(lái);
C>type file.c
computer and c
證明了在file1.c 文件中已存入了"computer and c"的信息。
二、fread函數(shù)和fwrite函數(shù)
ANSI C標(biāo)準(zhǔn)提出設(shè)置兩個(gè)函數(shù)(fread和fwrite),用來(lái)讀寫(xiě)一個(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:要讀寫(xiě)的字節(jié)數(shù)。
count:要進(jìn)行讀寫(xiě)多少個(gè)size字節(jié)的數(shù)據(jù)項(xiàng)。
fp:文件型指針。
如果文件以二進(jìn)制形式打開(kāi),用fread和fwrite函數(shù)就可以讀寫(xiě)任何類(lèi)型的信息,如:
fread(f,4,2,fp);
其中f是一個(gè)實(shí)型數(shù)組名。一個(gè)實(shí)型變量占4個(gè)字節(jié)。這個(gè)函數(shù)從fp所指向的文件讀入2次(每次4個(gè)字節(jié))數(shù)據(jù),存儲(chǔ)到數(shù)組f中。
如果有一個(gè)如下的結(jié)構(gòu)體類(lèi)型:
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ù)已存放在磁盤(pán)文件中,可以用下面的for語(yǔ)句和fread函數(shù)讀入40個(gè)學(xué)生的數(shù)據(jù):
for(i=0;i<40;i++)
fread(&stud[i],sizeof(struct student_type),l,fp);
同樣,以下for語(yǔ)句和fwrite函數(shù)可以將內(nèi)存中的學(xué)生數(shù)據(jù)輸出到磁盤(pán)文件中去:
for(i=0;i<40,i++)
fwrite(&stud[i],sizeof(struct student_type),l,fp);
如果fread或fwrite調(diào)用成功,則函數(shù)返回值為count的值,即輸人或輸出數(shù)據(jù)項(xiàng)的完整個(gè)數(shù)。
11.4.3 fprintf函數(shù)和fscanf函數(shù)
它們的一般調(diào)用方式為:
fprintf(文件指針,格式字符串,輸出表列);
fscanf(文件指針,格式字符串,輸入表列);
例如:
fprintf(fp,"%d,%6.2f",i,t);
它的作用是將整型變量i和實(shí)型變量t的值按%d和%6.2f的格式輸出到fp指向的文件上。