所謂“文件”是指一組相關數據的有序集合,該數據的集合的名字就是文件名。文件可以分為很多類,如源程序文件、目標文件、可執行文件、庫文件等等。
文件通常是存放在外部介質上的(例如磁盤等),在使用時才會被調入內存中并執行。從用戶的角度來看文件可以分為普通文件和設備文件。
普通文件是指存放在磁盤或者其它外部介質上的一個有序的集合,可以是源文件、目標文件、可執行程序等;也可以是一組待輸入處理的原始數據,或是一組輸出的結果。對于源文件、目標文件、可執行程序可以稱作程序文件,而輸入輸出數據可以稱作數據文件。
設備文件是指與主機相聯的各種外部設備,如顯示器、打印機、鍵盤等。在操作系統中,把外部設備也看作是一個文件來進行管理,把他們的輸入輸出等同于對磁盤文件的讀寫。
從文件編碼的形式來看,文件可以分為ASCII碼文件和二進制碼文件。ASCII碼文件也稱作為文本文件,這種文件在磁盤中存放時每個字符對應一個字節,用于存放相應的ASCII碼。
二進制文件是以二進制編碼的方式來編寫文件的。二進制文件雖然可以顯示在屏幕上,但是卻不能讀懂。
文件的指針
在C語言中用一個指針變量指向一個文件,那么這個指針稱為文件指針。另外,我們通過文件指針就可以對所指的文件進行各種操作。
一般形式為:
FILE* 文件變量標識符
解釋:FILE應該是大寫的,它實際上是由系統定義的一個結構體,該結構體包含了文件名、文件狀態和文件當前位置等信息,因此在編寫程序的時候我們不需要過于關心FILE結構的細節部分。
// 案例1:
FILE *fp;
/*說明:
fp表示FILE結構的指針變量,通過fp可以找到存放某一個文件信息的結構變量,
然后按照結構體提供的信息找到該文件,并對文件進行操作。*/
文件的打開和關閉
文件在進行讀寫操作之前,要打開文件,當使用完后應關閉文件。打開文件就是建立文件的各種有關信息,并使文件指針指向文件,以便進行其他操作。而關閉文件就是切斷文件指針和文件之間的關系,換而言之,就是禁止利用指針操作文件。
在C語言中,文件操作都是由庫函數完成的。如fopen 和 fclose。
1. 文件的打開 fopen()
fopen() 函數是用來打開一個文件,其一般的調用形式為:
文件指針名 = fopen(文件名,使用文件的方式);
注釋:
- 文件指針名:必須被說明為FILE類型的指針變量;
- 文件名:被打開文件的文件名;
- 使用文件的方式:文件的類型和操作要求
// 案例2:
FILE* fp;
fp = fopen("text","r");
/*說明:
在當前目錄下打開文件text,只允許“讀”的操作,并且讓fp指針指向該文件*/
使用文件的方式有12種,如下所示:
|使用文件方 | 意義 |
|----------|------------------------------:|
|“rt” | 只讀打開一個文本,只允許讀|
|“wt” | 只寫打開或者建立一個文件,只允許寫數據|
|“at” | 追加打開一個文件,并在文件末尾寫數據|
|“rb” | 只讀打開一個二進制文件,只允許讀|
|“wt” | 只寫打開或者建立一個而進制文件,只允許寫|
|“ab” | 追加打開一個二進制文件,并在文件末尾寫數據|
|“rt+” | 讀寫打開一個文件,允許讀和寫 |
| “wt+” | 讀寫打開或建立一個文件,允許讀寫|
|“at+” | 讀寫打開一個文件,允許讀,或在文件末尾追加數據|
|“rb+” | 讀寫打開一個二進制文件,允許讀寫|
|“wb+” | 讀寫打開或者建立一個二進制文件,允許讀寫 |
|“ab+” | 讀寫打開一個二進制文件,允許讀,或在文件末追加數據|
說明:
由r、w、a、t、b、+六個字符拼成,個字符的意義:
- r(read):讀
- w(write):寫
- a(append):追加
- t(text):文本文件,可省略不寫
- b(banary):二進制文件
6.+:讀和寫
// 案例3:
FILE* fp;
fd = fopen("./text","r");
if (NULL == fd)
{
printf("open error\n");
exit(1);
}
// 用讀“r”的方式打開文件“./text”;若文件打開失敗時,fp為空,輸出open error。
2. 文件的關閉
fclose()函數是指當文件使用完后,需要關閉文件。其一般形式為:
fclose(文件指針);
// 案例4:
fclose(fp);
// 說明:正常關閉文件時,fclose()函數的返回值是0。若返回一個非零的值,則表示關閉文件時發生錯誤
文件的讀寫
文件的讀寫是有多重方式的,它可以一個字節一個字節的讀或寫,也可以是一串一串的讀或寫。文件的讀寫可以分為下面四類,且它們的頭文件均是<stdio.h>。
1. 字符讀寫函數fgetc 和 fputc
字符的讀寫函數是以字節為單位讀寫函數。每一次可以從文件讀出或向文件內寫入一個字符。
讀字符函數fgetc() 的一般形式:
字符變量 = fgetc(文件指針);
說明:將文件中的一個字符讀取出來,然后存放在字符變量中。
寫字符函數fputs() 的一般形式:
fputs(字符量,文件指針);
說明:將字符量中的字符,存放在想對應的文件中。
// 案例5:
#include<stdio.h>
int main()
{
FILE* fp = fopen("./text","r");
if (NULL == fp)
{
printf("cann't open the file\n");
exit(1);
}
char ch;
// 讀取文件中的字符,一個一個的讀取。
ch = fgetc(fp);
while (EOF != ch) // EOF表示讀到文件的末尾
{
printf("%c\n",ch);
ch = fgetc(fp);
}
close(fp);
// 向文件中寫入數據
fp = fopen("./text1","w");
if (NULL == fp)
{
printf("cann't open the file\n");
exit(1);
}
printf("input a character:");
scanf("%c",&ch);
fputc(ch,fp); // 將ch變量中的字符存放到文件“./text1”中。
return 0;
}
注意:在網文件中寫數據的時候,上的那種寫法是,直接覆蓋文件中的數據,而不是在文件的末尾追加數據。若想不改變文件原來的數據,只想在文件的末尾追加數據,那么需要將文件的打開方式“w”更改為“a”,這樣我們就可以在原數據的基礎上追加數據。
2. 字符串讀寫函數fgets 和 fputs
fgets() 的一般形式:
fgets(字符數組名,n,文件指針);
說明:n是一個正整數,表示從文件中讀取的字符串不超過n-1個字符,在讀入最后一個字符后加上結束符'\0'。
fputs()的一般形式:
fputs(字符數組名,文件指針);
說明:字符數組名,首先其中必須是一個已被初始化的字符數組,即里面有值;也可以用一個字符串常量(或指針變量)代替字符數組名。
//案例6:
#include<stdio.h>
int main()
{
char ch[20];
FILE *fp = fopen("./text","rw");
if (NULL == fp)
{
printf("open error\n");
exit(1);
}
printf("input what you want to say:");
scanf("%s",ch);
//將字符串ch中的值寫在文件text中。
fputs(ch,fp);
char ch2[30];
// 從文件中讀取數據,并由ch2字符串變量接收。
fgets(ch2,sizeof(ch2)-1,fp);
printf("ch2:%s\n",ch2);
return 0;
}
3. 數據塊讀寫函數fread 和fwrite
C語言中不僅提供了字符、字符串的讀寫方式,同時也提供了數據塊的讀寫方式。它們可用來讀寫一組數據,如:一個數組元素,一個結構變量的值等。
fread()的一般形式:
fread(buffer,size,count,fp);
fwrite()的一般形式:
fwrite(buffer,size,count,fp);
說明:
- buffer 是一個指針,在fread函數中表示存放數據的首地址。在fwrite函數中表示輸出數據的首地址;
- size 表示數據塊的字節數;
- count 表示要讀寫的數據塊的塊數
- fp 表示文件的指針
//案例7:
#include<stdio.h>
struct student
{
int id;
char name[20];
float score;
};
int main()
{
struct student boy[2];
int i = 0;
for (;i < 2; i++)
{
printf("input the student's infomation(id, name, score):");
scanf("%d%s%f",&boy[i]->id,boy[i]->name,&boy[i]->score);
}
FILE* fp;
fp = fopen("./student.text","w+");
if (NULL == fp)
{
printf("open file error\n");
exit(1);
}
fwrite(boy,sizeof(struct student),2,fp);
rewind(fp);
struct student stu[2];
fread(stu,sizeof(struct student),2,fp);
printf("id\tname\tscore\n");
for (i = 0; i < 2; i++)
{
printf("%d\t%s\t%f\n",stu[i]->id,stu[i]->name,stu[i]->score);
}
return 0;
}
4. 格式化讀寫函數fscanf 和 fprintf
fscanf、fprintf和scanf、printf的區別:
fscanf和fprintf函數的讀寫不是對鍵盤和顯示器的,而是對磁盤文件;不過它們都是格式化讀寫函數。
fscanf 的一般形式:
fscanf(文件指針, 格式字符串, 輸入列表);
fprintf 的一般形式:
fprintf(文件指針, 格式字符串, 輸出列表);
//案例8:
#include<stdio.h>
int main()
{
char caBuf[3][32] = {'\0'};
int i = 0;
for (; i < 3; i++)
{
printf("input :");
scanf("%s", caBuf[i]);
}
FILE *fp;
fp = fopen("./MyInput", "wb+");
if (NULL == fp)
{
printf("open file error\n");
exit(1);
}
for (i=0; i < 3; i++)
{
fprintf(fp, "%s", caBuf[i]);
}
rewind(fp);
char sMsg[32] = {'\0'};
for(i=0; i < 3; i++)
{
fscanf(fp, "%s", sMsg);
printf("sMsg: %s\n", sMsg);
}
fclose(fp);
return 0;
}
文件定位
有的時候我們在讀寫文件時,不想從開頭或者末尾開始讀或者寫;想讀取中間的內容,或者是想將一段數據插入到文件中間,我們該怎么做?這時候,我們就需要引入新的知識,文件的定位。
文件定位函數
在文件定位中,主要有兩個函數:rewind()和fseek().
rewind() 在前面已經使用,并進行一定的說明,不過在這里還是要重申一下,其一般形式為:
rewind(文件指針);
功能:文件內部的文件指針轉移到文件首部。
fseek() 的一般形式:
fseek(文件指針, 位移量, 起始點);
參數說明:
文件指針:被指向移動的文件;
位移量:表示移動的字節數;
起始點:表示從何處開始計算位移量,規定有三種:文件首部(SEEK_SET,1),當前位置(SEEK_CUR,0)和文件尾部(SEEK_END, 2)。
// 案例10:
fseek(fp, 100, 0);
//表示:把文件位置指針移到距離首部100個字節處。
注意事項:fseek()一般用于二進制文件。在文本文件中由于要進行轉換,故往往計算位置會出現錯誤