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