第十三章 檔案
學習要求:
1.理解檔案的概念
2.掌握檔案的開啟與關閉的方法
3.掌握檔案的讀寫、定位及出錯檢測的方法
內容:
C檔案概述
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函數值置零。 |