1、“文件(file)”:所謂“文件”是指一組相關數據的有序集合。數據以文件的形式存放在外部介質(一般是磁盤、磁帶、光盤等)上,在操作系統中是以文件爲單位對數據進行管理的。以文件名作爲訪問文件的標識。
2、C語言把文件看作一個字節序列,即由一連串的字節組成。根據文件中的數據組織形式,數據文件可分爲ASCII碼文件和二進制文件。
ASCII碼文件,又稱爲“文本文件”(text),其每一個字節存放一個ASCII碼。
二進制文件,把內存中的數據按其在內存中的存儲形式存放在磁盤上。
例:十進制整數10000,在內存中佔兩個字節,其存放形式是:00100111,00010000。在二進制文件中也按這種方式存放。
但是,在ASCII文件中,十進制整數10000存放爲31H、30H、30H、30H、30H,佔五個字節,它們分別是1、0、0、0、0、0字母的ASCII碼。
3、按照操作系統對磁盤文件的讀寫方式,文件可以分爲“緩衝文件系統”和“非緩衝文件系統”。
緩衝文件系統:操作系統在內存中爲每一個正在使用的文件開闢一個讀寫緩衝區。從內存向磁盤輸出數據必須先送到內存中的緩衝區,裝滿緩衝區後才一起送到磁盤上。如果從磁盤向內存讀入數據,則一次從磁盤文件將一批數據輸入到內存緩衝區,然後再從緩衝區逐個地將數據送到程序數據區。
非緩衝文件系統:指操作系統不自動開闢確定大小的讀寫緩衝區,而由程序爲每個文件設定緩衝區。
在UNIX系統下,用緩衝文件系統來處理文本文件,用非緩衝文件系統處理二進制文件。ANSI C標準只採用緩衝文件系統。
在C語言中,沒有輸入輸出語句,對文件的讀寫都是用庫函數來實現的。本章只介紹ANSI C標準規定的緩衝文件系統。
文件類型指針
緩衝文件系統中,每一個使用的文件都在內存中開闢一個“文件信息區”,用來存放文件的相關信息(文件的名字、文件當前的讀寫位置、文件操作方式等)。這些信息保存在一個結構體變量中,該結構體是由系統定義的,取名爲FILE。Turbo C 3.0 在stdio.h文件中有以下文件類型的聲明:
typedef struct {
int level; /* 緩衝區“滿”或“空”的程度 */
unsigned flags; /* 文件狀態標誌 */
char fd; /* 文件描述符*/
unsigned char hold; /* 如無緩衝區不讀取字符 */
int bsize; /* 緩衝區的大小 */
unsigned char *buffer; /* 數據緩衝區的位置*/
unsigned char *curp; /* 指針,當前的指向 */
unsigned istemp; /* 臨時文件,指示器 */
short token; /* 用於有效性檢查 */
} FILE;
定義文件指針變量的一般形式爲:
FILE *文件結構指針變量名
例如:FILE *fp;
注意:只有通過文件指針,才能調用相應的文件。
文件的打開(fopen函數)
文件操作的過程:對磁盤文件的操作必須“先打開,後讀寫,最後關閉”。
“打開”文件的含義:以某中方式從磁盤上查找指定的文件或創建一個新文件。
ANSI C規定了標準輸入輸出函數庫,用 fopen()函數打開文件。fopen()函數的調用方式一般爲:
FILE *fp;
fp=fopen(文件名,使用文件方式);
例如:
FILE *fp;
aaaafp = fopen("file1","r");
表示要打開名字爲file1的文件,使用文件方式爲“讀入”,如果打開成功,返回一個指向file1文件的指針;如果打開失敗,返回一個NULL指針。
使用文件方式見下表:
使用文件方式 |
含義 |
"r"(只讀) | 爲輸入打開一個文本文件 |
"w"(只寫) | 爲輸出打開一個文本文件 |
"a"(追加) | 爲追加打開一個文本文件 |
"rb"(只讀) | 爲輸入打開一個二進制文件 |
"wb"(只寫) | 爲輸出打開一個二進制文件 |
"ab"(追加) | 爲追加打開一個二進制文件 |
"r+"(讀寫) | 爲讀/寫打開一個文本文件 |
"w+"(讀寫) | 爲讀/寫創建一個文本文件 |
"a+"(讀寫) | 爲讀/寫打開一個文本文件 |
"rb+"(讀寫) | 爲讀/寫打開一個二進制文件 |
"wb+"(讀寫) | 爲讀/寫創建一個二進制文件 |
"ab+"(讀寫) | 爲讀/寫打開一個二進制文件 |
說明:
1、用"r"方式打開的文件只能用於向計算機輸入而不能用作向該文件輸出數據,而且該文件應該已經存在,不能用"r"方式打開一個不存在的文件(即輸入文件),否則出錯。
2、用"w"方式打開的文件只能用於向該文件寫數據(即輸出文件),而不能用來向計算機輸入。如果原來不存在該文件,則在打開時新建一個文件,如果該文件存在,則先刪除該文件,然後重新建立一個新文件。
3、如果希望向文件尾添加新數據(不刪除原有數據),則應該用"a"方式打開。但要求此時文件必須存在,否則出錯。
4、用"r+"、"w+"、"a+"方式打開的文件即可以用來輸入數據,也可以用來輸出數據。
5、如果不能實現打開文件的任務,fopen()函數將帶回一個出錯信息。用帶"r"的方式("r"、"rb"、"r+"、"rb+")打開文件時,若文件不存在,則返回NULL指針。
常用以下方式打開文件:
FILE *fp;
if ((fp=fopen("file1", "r")) ==NULL )
{
printf("cannot open this file\n");
exit(0);
}
即如果有錯就在終端上輸出"cannot open this file"。exit()函數的作用是關閉所有文件,終止正在執行的程序。
6、在向計算機輸入文本文件時,將回車換行符轉換爲一個換行符,在輸出時把換行符轉換爲回車和換行兩個字符。在用二進制文件時,不進行轉換。
文件的關閉(fclose函數)
在使用完一個文件後應該關閉它,“關閉”文件就是使文件指針與文件脫離,此後不能再通過該指針對原來與其相聯繫的文件進行讀寫操作。應養成在程序終止前關閉所有文件的習慣。
用fclose函數關閉文件。fclose函數調用的一般形式爲:
fclose(文件指針)
例如:
fclose(fp);
fclose函數也帶回一個返回值,當順利關閉文件時,返回0,否則返回EOF(-1)。
文件的讀寫
當文件打開後,就可以對它進行讀寫了。常用的讀寫函數如下所述。
1、fputc函數和fgetc函數(putc函數和getc函數)
(1)、fputc函數
把字符寫入到磁盤文件,一般的調用方式爲:
fputc(ch,fp)
把字符(ch的值)寫入fp所指向的文件中去。成功時返回字符ch的ASCII碼,失敗時返回
EOF(在stdio.h中,符號常量EOF的值等於-1)。
(2)、fgetc()函數
從指定文件讀入一個字符。fgetc函數的調用形式爲:
ch=fgetc(fp);
從fp所指向的文件中讀一個字符,返回讀得的字符給變量ch。對於文本文件,遇文件尾時返回文件結束標誌EOF。對於二進制文件,用feof(fp) 判別是否遇文件尾,feof(fp)=1說明遇文件尾。
從文本文件中順序讀入文件內容,並在屏幕上顯示出來,可以用:
ch = fgetc(fp);
while(ch != EOF)
{
putchar(ch);
ch = fgetc(fp);
}
從二進制文件中順序讀入文件內容,可以用:
while(!feof(fp))
{
ch = fgetc(fp);
....
}
這種方法也適用於文本文件。
(3)、fputc函數和fgetc函數應用舉例
例子13_1 從鍵盤輸入一些字符,逐個把它們送入磁盤文件,直到從鍵盤輸入#爲止。
例子13_2 將一個磁盤文件的內容複製到另一個磁盤文件。
fread函數和fwrite函數
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];
}stu[40];
結構體數組stu有40個元素,每一個元素用來存放一個學生的數據。假設學生的數據已經存放在磁盤文件中,可以用下面的for語句和fread函數讀入40個學生的數據:
for(i=0; i<40; i++)
fread(&stu[i], sizeof(struct student_type), 1, fp);
或:
fread(&stu[i], sizeof(struct student_type), 40, fp);
同樣,以下程序可以將內存中的學生數據輸出到磁盤文件中去:
for(i=0; i<40; i++) /* 每次寫一個學生 */
fwrite(&stu[i], sizeof(struct student_type), 1, fp);
或者只寫一次
fwrite(stu, sizeof(struct student_type), 40, fp);
例子13_3 從鍵盤上輸入一批學生數據,然後存儲到磁盤上。
fprintf函數和fscanf函數
fprintf函數、fscanf函數與printf函數、scanf函數的作用相仿,都是格式化讀寫函數。fprintf和fscanf函數的讀寫對象是磁盤文件,而printf和scanf函數的讀寫對象是終端。
它們的一般調用格式爲:
fprintf(文件指針,格式字符串,輸出列表);
fscanf (文件指針,格式字符串,輸入列表);
除增加“文件指針”外,其他與printf()/scanf()用法相同。
例如:
fprintf(fp,"%d,%6.2f",i,t);
它的作用是將整型變量i和實型變量t的值按%d和%6.2f的格式輸出到fp所指向的文件中。如果i=3,t=4.5,則輸出到磁盤文件上的是以下字符串:
3,4.50
同樣,用fscanf函數可以從磁盤文件上讀入ASCII字符:
fscanf(fp,"%d,%f",&i,&t);
磁盤文件上如果有以下字符:3,4.5 則將磁盤文件的數據3送給變量i,4.5送給變量t。
用fprintf和fscanf函數對磁盤文件操作,由於在輸入時要將ASCII碼轉換爲二進制形式,在輸出時又要將二進制轉換爲字符,花費時間比較多,因此,在內存與磁盤頻繁交換數據的情況下,最好不用fprintf和fscanf函數,而用fread和fwrite函數。
其他讀寫函數
1、putw和getw函數
putw和getw函數用來對磁盤文件讀寫一個字(整數)。例如:
putw(10,fp); /* 整數10寫入文件fp */
i=getw(fp); /* 從文件fp讀一個整數給變量i */
2、fgets和fputs函數
fgets函數的作用是從指定文件讀入一個字符串。例如:
fgets(str, n,fp) /* 從文件fp讀n-1個字節到str,str最後一個字節加'\0'*/
fputs函數的作用是向指定的文件輸出一個字符串。例如:
fputs(str,fp) /* 把字符串str寫入fp */
文件的定位
文件中有一個位置指針,指向當前讀寫的位置。每當進行一次讀寫後,該指針自動指向下一個字符的位置。可以用ftell()函數獲得當前的位置指針,也可以用rewind()/fseek()函數改變位置指針,使其指向需要讀寫的位置。
1、rewind函數
一般的使用形式爲:rewind(fp);作用:使文件fp的位置指針指向文件開始。
例子13_4 把一個文件的內容顯示在屏幕上,並同時複製到另一個文件。
2、fseek函數和隨機讀寫
對流式文件可以進行順序讀寫,也可以進行隨機讀寫,關鍵在於控制文件的位置指針。
用fseek函數可以實現改變文件的位置指針。fseek函數的調用形式爲:
fssek (文件類型指針,位移量,起始點);
功能:把文件的位置指針從起始點開始,移動指定位移量的字節數。成功返回0,失敗返回非0。
起始點 | 符號常量 | 值 |
文件開始位置 | SEEK_SET | 0 |
當前位置 | SEEK_CUR | 1 |
文件尾 | SEEK_END | 2 |
例子13_5 在磁盤文件stud_dat上,存有10個學生(0~9)的數據,讀出1、3、5、7、9號學生數據,並在屏幕上顯示出來。
3、ftell函數
ftell函數的作用是得到流式文件中的當前位置,用相對於文件開頭的位移量來表示。若失敗則返回值爲-1L。
例如:
i=ftell(fp);
if(i==-1L) printf("error\n");
變量i存放當前位置,如調用函數時出錯(如不存在fp文件),則輸出"error"。
出錯的檢測
C 標準提供一些函數用來檢查輸入輸出函數調用中的錯誤。
1、ferror函數
在文件操作時,如果出錯,除了操作函數的返回值有所反應外(如fopen()函數返回NULL),還可以用ferror函數獲得是否出錯。它的一般調用形式爲:
ferror(fp)
功能:若上一次文件操作未出錯,返回0;否則返回非0。
2、clearerr函數
clearerr函數的作用是使文件錯誤標誌和文件結束標誌置爲0。 文件操作出現錯誤後,ferror(fp)函數值爲一個非0值,該錯誤信息將一直保留在系統中,在調用clearerr(fp)函數後,ferror(fp)函數值變成0。
文件輸入輸出小結
常用的緩衝文件系統函數
分類
|
函數名
|
功能
|
打開文件
|
fopen() |
打開文件。 |
關閉文件
|
fclose()
|
關閉文件。 |
文件定位
|
fseek() rewind() ftell() |
改變文件位置指針位置 使文件位置指針重新置於文件開頭 返回文件位置指針的當前值 |
文件讀寫
|
fgetc(),getc() fputc(),putc() fgets() fputs() getw() putw() fread() fwrite() fscanf() fprintf() |
從指定文件取得一個字符。 把字符輸出到指定文件。 從指定文件讀取字符串。 把字符串輸出到指定文件。 從指定文件讀取一個字(int型)。 把一個字(int型)輸出到指定文件。 從指定文件中讀取數據項。 把數據項寫到指定文件。 從指定文件按格式輸入數據。 按指定格式將數據寫到指定文件中。 |
文件狀態
|
feof() ferror() clearerr() |
若到文件末尾,函數值爲“真”(非0)。 若對文件操作出錯,函數值爲“真”(非0)。 使ferror和feof函數值置零。 |