在C語言中,文件操作都是由庫函數來完成的,我們就來總結文件的相關的操作。
fopen() 函數用來打開一個文件,它的格式為:
FILE *fopen(char *filename, char *type);
filename為文件名(包括文件路徑),type為打開方式,它們都是字符串。fopen() 會獲取文件信息,包括文件名、文件狀態、當前讀寫位置等,並將這些信息保存到一個FILE類型的結構體變量中,然後將該變量的地址返回。
如果接收 fopen() 的返回值,就需要定義一個 FILE 類型的指針。例如:
FILE *fp = ("demo.txt", "r");
上面是以“只讀”方式打開當前目錄下的 demo.txt 文件,並使 fp 指向該文件,這樣就可以通過 fp 來操作 demo.txt 了。fp 通常被稱為文件指針。又如:
FILE *fp = fopen("D:\\demo.txt","rb");
表示以二進制方式打開 D 盤下的 demo.txt 文件,允許讀和寫。
打開方式(mode)有多種:
使用文件方式 含義
“r”(只讀) 為輸入打開一個文本文件
“w”(只寫) 為輸出打開一個文本文件
“a”(追加) 為追加打開一個文本文件
“rb”(只讀) 為輸入打開一個二進制文件
“wb”(只寫) 為輸出打開一個二進制文件
“ab”(追加) 為追加打開一個二進制文件
“r+”(讀寫) 為讀/寫打開一個文本文件
“w+”(讀寫) 為讀/寫創建一個文本文件
“a+”(讀寫) 為讀/寫打開一個文本文件
“rb+”(讀寫) 為讀/寫打開一個二進制文件
“wb+”(讀寫) 為讀/寫創建一個二進制文件
“ab+”(讀寫) 為讀/寫打開一個二進制文件
在打開一個文件時,如果出錯,fopen將返回一個空指針值NULL,因此,我們可以在程序中這樣來處理
if( (fp=fopen("D:\\demo.txt","rb") == NULL ){ printf("open file is error D:\\demo.txt file!"); getchar(); exit(1); }
如果再打開文件是,返回的指針為空,則表示不能打開D盤跟目錄下的demo.txt 文件,輸出提示的錯誤信息!!printf(“open file is error D:\demo.txt file!”);
fp 為文件指針。例如:
fclose(fp);
文件正常關閉時,fclose() 的返回值為0,如果返回非零值則表示有錯誤發生。
下面這段摘自網上:
從文件編碼的方式來看,文件可分為ASCII碼文件和二進制碼文件兩種。
ASCII文件也稱為文本文件,這種文件在磁盤中存放時每個字符對應一個字節,用於存放對應的ASCII碼。例如,數5678的存儲形式為:
ASC碼: 00110101 00110110 00110111 00111000
↓ ↓ ↓ ↓
十進制碼: 5 6 7 8 共占用4個字節。ASCII碼文件可在屏幕上按字符顯示, 例如源程序文件就是ASCII文件,用DOS命令TYPE可顯示文件的內容。 由於是按字符顯示,因此能讀懂文件內容。
二進制文件是按二進制的編碼方式來存放文件的。 例如, 數5678的存儲形式為: 00010110 00101110只占二個字節。二進制文件雖然也可在屏幕上顯示, 但其內容無法讀懂。C系統在處理這些文件時,並不區分類型,都看成是字符流,按字節進行處理。 輸入輸出字符流的開始和結束只由程序控制而不受物理符號(如回車符)的控制。 因此也把這種文件稱作“流式文件”。
一個文件可以以文本模式或二進制模式打開,這兩種的區別是:在文本模式中回車被當成一個字符’/n’,而二進制模式認為它是兩個字符0x0D,0x0A;如果在文件中讀到0x1B,文本模式會認為這是文件結束符,也就是二進制模型不會對文件進行處理,而文本方式會按一定的方式對數據作相應的轉換。
以字符形式讀寫文件時,每次可以從文件中讀取一個字符,或者向文件中寫入一個字符。主要使用兩個函數:fgetc()和fputc()。
fgetc 是 file get char 的縮寫,意思是從指定的文件中讀取一個字符。它的原型為:
int fgetc (FILE *fp);
fp 為文件指針。fgetc() 讀取成功時返回讀取到的字符,讀取到文件末尾或讀取失敗時返回EOF。
EOF 是 end of file 的縮寫,表示文件末尾,是在 stdio.h 中定義的宏,它的值是一個負數,往往是 -1。返回值類型之所以為 int,就是為了容納這個負數(char不能是負數)。
EOF 不絕對是 -1,也可以是其他負數,這要看編譯器的實現。
fgetc() 使用舉例:
char ch; FILE *fp = fopen("D:\\demo.txt", "r+"); ch = fgetc(fp);
表示從D:\demo.txt文件中讀取一個字符,並保存到變量ch中。
在文件內部有一個位置指針,用來指向當前讀寫到的位置,也就是讀寫到第幾個字節。在文件打開時,該指針總是指向文件的第一個字節。使用fgetc 函數後,該指針會向後移動一個字節,所以可以連續多次使用fgetc讀取多個字符。
注意:這個文件內部的位置指針與C語言中的指針不是一回事。位置指針僅僅是一個標志,表示文件讀寫到的位置,也就是讀寫到第幾個字節,它不表示地址。文件每讀寫一次,位置指針就會移動一次,它不需要你在程序中定義和賦值,而是由系統自動設置,對用戶是透明的。
實例:
#includeint main(){ FILE *fp; char ch; //如果文件不存在,給出提示並退出 if( (fp=fopen("D:\\demo.txt","rt")) == NULL ){ printf("Cannot open file, press any key to exit!"); getch(); exit(1); } //每次讀取一個字節,直到讀取完畢 while( (ch=fgetc(fp)) != EOF ){ putchar(ch); } putchar('\n'); //輸出換行符 fclose(fp); return 0; }
在D盤下創建demo.txt文件,輸入任意內容並保存,運行程序,就會看到剛才輸入的內容全部都顯示在屏幕上。
該程序的功能是從文件中逐個讀取字符,在屏幕上顯示,直到讀取完畢。
程序第14行是關鍵,while 循環的條件為(ch=fgetc(fp)) != EOF。fget() 每次從位置指針所在的位置讀取一個字符,並保存到變量 ch,位置指針向後移動一個字節。當文件指針移動到文件末尾時,fget() 就無法讀取字符了,於是返回 EOF,表示文件讀取結束了。
EOF 本來表示文件末尾,意味著讀取結束,但是很多函數在讀取出錯時也返回 EOF,那麼當返回EOF時,到底是文件讀取完畢了還是讀取出錯了?我們可以借助 stdio.h 中的兩個函數來判斷,分別是 feof() 和 ferror()。
feof() 函數用來判斷文件內部指針是否指向了文件末尾,它的原型是:
int feof ( FILE * fp );
當指向文件末尾時返回非零值,否則返回零值。
ferror() 函數用來判斷文件操作是否出錯,它的原型是:
int ferror ( FILE *fp );
出錯時返回非零值,否則返回零值。
需要說明的是,文件出錯是非常少見的情況,上面的示例基本能夠保證將文件內的數據讀取完畢。如果追求完美,也可以加上判斷並給出提示:
#includeint main(){ FILE *fp; char ch; //如果文件不存在,給出提示並退出 if( (fp=fopen("D:\\demo.txt","rt")) == NULL ){ printf("Cannot open file, press any key to exit!"); getch(); exit(1); } //每次讀取一個字節,直到讀取完畢 while( (ch=fgetc(fp)) != EOF ){ putchar(ch); } putchar('\n'); //輸出換行符 if(ferror(fp)){ puts("讀取出錯"); }else{ puts("讀取成功"); } fclose(fp); return 0; }
這樣,不管是出錯還是正常讀取,都能夠做到心中有數。
fputc 是 file output char 的所以,意思是向指定的文件中寫入一個字符。調用的形式為:
int fputc ( int ch, FILE *fp );
ch 為要寫入的字符,fp 為文件指針。fputc() 寫入成功時返回寫入的字符,失敗時返回EOF,返回值類型為 int 也是為了容納這個負數。例如:
fputc('a', fp);
或
char ch = 'a'; fputc(ch, fp);
表示把字符 ‘a’ 寫入fp所指向的文件中。
兩點說明:
1) 被寫入的文件可以用寫、讀寫、追加方式打開,用寫或讀寫方式打開一個已存在的文件時將清除原有的文件內容,並將寫入的字符放在文件開頭。如需保留原有文件內容,並把寫入的字符放在文件末尾,就必須以追加方式打開文件。不管以何種方式打開,被寫入的文件若不存在時則創建該文件。
2) 每寫入一個字符,文件內部位置指針向後移動一個字節。
#includeint main(){ FILE *fp; char ch; //判斷文件是否成功打開 if( (fp=fopen("D:\\demo.txt","wt+")) == NULL ){ printf("Cannot open file, press any key to exit!\n"); getch(); exit(1); } printf("Input a string:\n"); //每次從鍵盤讀取一個字符並寫入文件 while ( (ch=getchar()) != '\n' ){ fputc(ch,fp); } fclose(fp); return 0; }
運行程序,輸入一行字符並按回車鍵結束,打開D盤下的demo.txt文件,就可以看到剛才輸入的內容。
上面一個模塊fgetc()和fputc()函數每次只能讀寫一個字符,速度比較慢,在實際過程中是每次讀寫一個字符串或者一個數據塊,這樣能明顯提高效率。
fgets() 函數用來從指定的文件中讀取一個字符串,並保存到字符數組中,它的原型為:
char *fgets ( char *str, int n, FILE *fp );
str 為字符數組,n 為要讀取的字符數目,fp 為文件指針。
返回值:讀取成功時返回字符數組首地址,也即 str;讀取失敗時返回 NULL;如果開始讀取時文件內部指針已經指向了文件末尾,那麼將讀取不到任何字符,也返回 NULL。
讀取到的字符串會在末尾自動添加 ‘\0’,n 個字符也包括 ‘\0’。也就是說,實際只讀取到了 n-1 個字符,如果希望讀取 100 個字符,n 的值應該為 101。例如:
#define N 101 char str[N]; FILE *fp = fopen("D:\\demo.txt", "r"); fgets(str, N, fp);
表示從 D:\demo.txt 中讀取100個字符,並保存到字符數組str中。
需要重點說明的是,在讀取到 n-1 個字符之前如果出現了換行,或者讀到了文件末尾,則讀取結束。這就意味著,不管n的值多大,fgets() 最多只能讀取一行數據,不能跨行。在C語言中,沒有按行讀取文件的函數,我們可以借助 fgets(),將n的值設置地足夠大,每次就可以讀取到一行數據。
一行一行的讀取文件,代碼如下:
#include#include #define N 100 int main(){ FILE *fp; char str[N+1]; if( (fp=fopen("d:\\demo.txt","rt")) == NULL ){ printf("Cannot open file, press any key to exit!\n"); getch(); exit(1); } while(fgets(str, N, fp) != NULL){ printf("%s", str); } fclose(fp); system("pause"); return 0; }
在這個D:\demo.txt:文件中寫入下面的內容:
My Name is Android
Google
那麼編譯運行上面的程序,結果為:
My Name is Android Google 請按任意鍵繼續...
fputs 函數是指想一個文件中寫入一個字符串,它的原型為:
int fputs(char *str,FILE *fp);
str為要寫入的字符串,fp為文件指針,寫入成功返回非負數,失敗返回EOF。
eg:
char *str = "xuhao"; FILE *fp = fopen("D:\\demo.text","a+");
表示把字符串str寫入到D:\demo.txt文件中。
在上述代碼中建立的D:\demo.txt 文件中追加一個字符串。
#includeint main(){ FILE *fp; char str[102] = {0}, strTemp[100]; if( (fp=fopen("D:\\demo.txt", "at+")) == NULL ){ printf("Cannot open file, press any key to exit!\n"); getch(); exit(1); } printf("Input a string:"); gets(strTemp); strcat(str, "\n"); strcat(str, strTemp); fputs(str, fp); fclose(fp); return 0; }
編譯並運行程序,在彈出的視圖中 輸入java C++,打開 D:\demo.txt,文件內容為:
My Name is Android Google java C++
比如文件復制,代碼如下:
void main(){ char *read_path = "E:\\dongnao\\vip\\ndk\\08_08_C_05\\files\\liuyan.png"; char *write_path = "E:\\dongnao\\vip\\ndk\\08_08_C_05\\files\\liuyan_new.png"; //讀的文件 b字符表示操作二進制文件binary FILE *read_fp = fopen(read_path, "rb"); //寫的文件 FILE *write_fp = fopen(write_path, "wb"); //復制 int buff[50]; //緩沖區域 int len = 0; //每次讀到的數據長度 while ((len = fread(buff, sizeof(int), 50, read_fp)) != 0){ //將讀到的內容寫入新的文件 fwrite(buff,sizeof(int),len,write_fp); } //關閉流 fclose(read_fp); fclose(write_fp); getchar(); }
//獲取文件的大小 void main(){ char *read_path = "E:\\dongnao\\vip\\ndk\\08_08_C_05\\files\\liuyan.png"; FILE *fp = fopen(read_path, "r"); //重新定位文件指針 //SEEK_END文件末尾,0偏移量 fseek(fp,0,SEEK_END); //返回當前的文件指針,相對於文件開頭的位移量 long filesize = ftell(fp); printf("%d\n",filesize); getchar(); }
常用的文件操作也就上面的幾種了,有關文件的加密和解密,二進制文件的加密和解密,可能後面應該會結合JNI調用和NDK開發和實現的,好了,這篇文章到此為止!