程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言入門知識 >> C語言(七)文件的相關操作

C語言(七)文件的相關操作

編輯:C語言入門知識

C語言文件的打開與關閉


在C語言中,文件操作都是由庫函數來完成的,我們就來總結文件的相關的操作。

文件的打開(fopen函數)

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!”);

文件關閉(fclose函數)

fp 為文件指針。例如:

fclose(fp);

文件正常關閉時,fclose() 的返回值為0,如果返回非零值則表示有錯誤發生。

C中文本文件和二進制文件的區別

下面這段摘自網上:

從文件編碼的方式來看,文件可分為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,文本模式會認為這是文件結束符,也就是二進制模型不會對文件進行處理,而文本方式會按一定的方式對數據作相應的轉換。


C語言以字符形式讀寫文件

以字符形式讀寫文件時,每次可以從文件中讀取一個字符,或者向文件中寫入一個字符。主要使用兩個函數:fgetc()和fputc()。

字符讀取函數 fgetc

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語言中的指針不是一回事。位置指針僅僅是一個標志,表示文件讀寫到的位置,也就是讀寫到第幾個字節,它不表示地址。文件每讀寫一次,位置指針就會移動一次,它不需要你在程序中定義和賦值,而是由系統自動設置,對用戶是透明的。

實例:

#include
int 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,那麼當返回EOF時,到底是文件讀取完畢了還是讀取出錯了?我們可以借助 stdio.h 中的兩個函數來判斷,分別是 feof() 和 ferror()。

feof() 函數用來判斷文件內部指針是否指向了文件末尾,它的原型是:

int feof ( FILE * fp );

當指向文件末尾時返回非零值,否則返回零值。

ferror() 函數用來判斷文件操作是否出錯,它的原型是:

int ferror ( FILE *fp );

出錯時返回非零值,否則返回零值。

需要說明的是,文件出錯是非常少見的情況,上面的示例基本能夠保證將文件內的數據讀取完畢。如果追求完美,也可以加上判斷並給出提示:

#include
int 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

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) 每寫入一個字符,文件內部位置指針向後移動一個字節。

#include
int 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文件,就可以看到剛才輸入的內容。


C語言以字符串形式讀寫文件

上面一個模塊fgetc()和fputc()函數每次只能讀寫一個字符,速度比較慢,在實際過程中是每次讀寫一個字符串或者一個數據塊,這樣能明顯提高效率。

讀字符串函數fgets

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

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 文件中追加一個字符串。

#include
int 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++ 

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開發和實現的,好了,這篇文章到此為止!

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved