閱讀564 返回首頁    go 阿裏雲 go 技術社區[雲棲]


C語言文件操作

        文章出自:海子

        修改:㈠輩子、戀蒶——標哥

                                          C語言文件操作解析(二)

       C語言中對文件進行操作必須首先打開文件,打開文件主要涉及到fopen函數。fopen函數的原型為

       FILE* fopen(const char *path,const char *mode)

       其中path為文件路徑,mode為打開方式

       1)對於文件路徑,隻需注意若未明確給出絕對路徑,則默認該文件在工程的目錄下。若需給出絕對路徑,則注意轉義字符'\',比如有文件test.txt存放在C盤根目錄下,則文件路徑參數值應為C:\\test.txt。//因為C語言中兩個\\才輸出一個\

       2)對於mode,主要由r,w,a,+,b,t六個字符組合而成。

        r:隻讀方式,文件必須存在

        w:隻寫方式,若文件存在,則原有內容會被清除;若文件不存在,則會建立文件

        a:追加方式打開隻寫文件,隻允許進行寫操作,若文件存在,則添加的內容放在文件末尾;若不存在,則建立文件

        +:可讀可寫

        b:以二進製方式打開文件

        t:以文本方式打開文件(默認方式下以文本方式打開文件)

   下麵是常見的組合:

        r:      以隻讀的方式打開文件,隻允許讀,此文件必須存在,否則返回NULL,打開成功後返回文件指針,位置指針指向文件頭部

        r+:    以可讀可寫的方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功後返回文件指針,位置指針指向文件頭部

        rb+:  以可讀可寫、二進製方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功後返回文件指針,位置指針指向文件頭部       

        rt+:  以可讀可寫、文本方式打開文件,允許讀寫,此文件必須存在,否則返回NULL,打開成功後返回文件指針,位置指針指向文件頭部       

        w:    以隻寫的方式打開文件,隻允許寫,若文件存在,文件中原有內容會被清除;若文件不存在,則創建文件,打開成功後返回文件指針,位置指針指向文件頭部

        w+:  以讀寫的方式打開文件,允許讀寫,若文件存在,文件中原有內容會被清除;若文件不存在,則創建文件,打開成功後返回文件指針,位置指針指向文件頭部

        a:     以追加、隻寫的方式打開文件,隻允許寫。若文件存在,則追加的內容添加在文件末尾,若文件不存在,則創建文件。打開成功後返回文件指針,位置指針指向文件頭部(注意很多書上或資料上講述追加方式打開成功後位置指針指向文件末尾是錯誤的)

        a+:   以追加、可讀寫的方式打開文件,允許讀寫。若進行讀操作,則從頭開始讀;若進行寫操作,則將內容添加在末尾。若文件不存在,則創建文件。打開成功後返回文件指針,位置指針指向文件頭部。

       其他方式類似。

下麵討論一下以二進製方式和文本方式打開文件有什麼區別。

       其實這兩種方式打開文件並沒有太大的區別,僅僅隻有一點區別就是在處理某些特殊字符的時候。

       以文本方式打開文件,若將數據寫入文件,如果遇到換行符'\n'(ASII 值為10,0A),則會轉換為回車—換行'\r\n'(ASII值為13,10,0D0A)存入到文件中,同樣讀取的時候,若遇到回車—換行,即連續的ASII值13,10,則自動轉換為換行符。

       而以二進製方式打開文件時,不會進行這樣的處理。

       還有如果以文本方式打開文件時,若讀取到ASCII碼為26(^Z)的字符,則停止對文件的讀取,會默認為文件已結束,而以二進製方式讀取時不會發生這樣的情況。由於正常情況下我們手動編輯完成的文件是不可能出現ASCII碼為26的字符,所以可以用feof函數去檢測文件是否結束。以上所述的兩點區別隻在windows下存在,在unix下沒有區別。

注意:1)在以追加方式打開文件時,位置指針指向文件的首部。

          在這裏區分一下位置指針和文件指針:

          文件指針:指向存儲文件信息的一個結構體的指針

          位置指針:對文件進行讀寫操作時移動的指針

          在頭文件<stdio.h>中存在一個結構體_iobuf,在VC6.0中選中FILE,然後F12,則可以看到_iobuf的具體定義:

複製代碼
struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;
複製代碼

          比如用FILE *fp定義了一個文件指針,並成功打開一個文件之後,fp隻是指向該結構體,而在對文件進行讀寫操作時,fp的值並不會改變,改變的是結構體中_ptr的值,這個_ptr就是位置指針。

      2)以追加方式打開時,若進行寫操作,則rewind函數和fseek函數不會起到作用,因為以追加方式打開時進行寫操作的話,係統會自動將位置指針移動到末尾

      3)當文件打開用於更新時,可以通過文件指針對文件進行讀寫操作,但是如果沒有給出fseek或者rewind的話,讀操作後麵不能直接跟寫操作,否則會是無效的寫操作(位置指針會移動,但是需要寫入文件的內容不會被寫入到文件當中),但是寫操作後可以直接跟讀操作。

         

1.測試程序

假設工程目錄下已存在文件test.txt,文件中含有的字符串為"ABC"

複製代碼
/*測試fopen函數以追加方式打開文件時初始指針的位置 2011.10.5*/

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    int n;
    FILE *fp;
    if((fp=fopen("test.txt","a"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    n=ftell(fp);     //得到此時fp所處位置距文件首的偏移字節數
     printf("%d\n",n);
    fputs("test",fp);
    n=ftell(fp);
    printf("%d\n",n);
    fclose(fp);
    return 0;
}
複製代碼

輸出結果為:

0
7
Press any key to continue
由輸出結果可知,初始打開文件後,指針是位於文件首部,隻是在往文件中添加內容時,才將文件指針移動到文件末尾。

2.測試程序

複製代碼
/*測試以二進製方式和文本方式打開文件的區別 2011.10.5*/ 

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    char ch;
    int i;
    char s[]={'A','B','\n','C'};
    FILE *fp1,*fp2;
    if((fp1=fopen("test1.txt","wt"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    if((fp2=fopen("test2.txt","wb"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    for(i=0;i<4;i++)
    {
        fputc(s[i],fp1);    //以文本方式向文件中寫入數據 
         fputc(s[i],fp2);    //以二進製方式向文件中寫入數據 
    }
    fclose(fp1);
    fclose(fp2);
    if((fp1=fopen("test1.txt","rt"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    if((fp2=fopen("test1.txt","rb"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    ch=fgetc(fp1);
    while(!feof(fp1))    //以文本方式從文件中讀取數據 
    {
        printf("%02X",ch);
        ch=fgetc(fp1);
    }
    printf("\n");
    ch=fgetc(fp2);
    while(!feof(fp2))   //以二進製方式從文件中讀取數據
    {
        printf("%02X",ch);
        ch=fgetc(fp2);
    }
    printf("\n");
    fclose(fp1);
    fclose(fp2);
    return 0;
}
複製代碼

在向文件中寫完數據後,用UltraEdit以二進製方式打開test1.txt和test2.txt,看到的結果如下:

根據得到的結果可知,以文本方式寫入時,多寫入了一個字符0D,即'\r'。

程序輸出結果:

41420A43
41420D0A43
請按任意鍵繼續. . .

分別以文本方式和二進製方式讀取test1.txt時,輸出的內容不同。

可知在以文本方式讀取時,對'\r\n'進行了轉換,而二進製方式讀取時卻沒有進行這樣的轉換。

3.測試程序

複製代碼
/*測試讀操作後能否直接跟寫操作 2011.10.5*/

#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    int ch;
    int n;
    FILE *fp;
    if((fp=fopen("test.txt","r+"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    fseek(fp,1L,0);  //將fp移動到距文件首1字節的位置    
     ch=fgetc(fp);
    printf("%c\n",ch);
    //rewind(fp);
    fseek(fp,1L,0);
    fputs("test",fp);
    ch=fgetc(fp);
    printf("%c\n",ch);
    fclose(fp);
    return 0;
}
複製代碼

假設工程已經存在文件test.txt,文件中含有字符串"ABCDEFGH"。

則上述程序執行結果為:

B
F
請按任意鍵繼續. . .文件中內容為"AtestFGH"。

與預想結果相同,因此讀取到字符'B'後,再將位置指針置到距文件首1字節處,即字符'B'處,寫入"test"後,會覆蓋掉"BCDE",寫完後位置指針指向字符'F',因此此時進行讀操作,得到的結果是'F'。

但是如果將fseek(fp,1L,0);這句注釋掉,則執行結果為:

B
G
請按任意鍵繼續. . .

文件中的內容為"ABCDEFGH"。

注釋掉fseek一句後,讀取完字符'B'後,位置指針指向字符'C',再進行寫操作,位置指針會向後移動4個字節的位置,指向字符'G',因此第二次讀取的輸出結果為'G'。但是文件中的內容沒有被改寫,相當於這次寫操作是無效操作。

4.測試程序

複製代碼
#include<stdio.h>
#include<stdlib.h>

int main(void)
{
    FILE *fp;
    int ch;
    if((fp=fopen("test","rb"))==NULL)
    {
        printf("can not open file\n");
        exit(0);
    }
    ch=fgetc(fp);
    while(feof(fp)==0)
    {
        printf("%02X\n",ch);
        ch=fgetc(fp);
    }
    fclose(fp);
    return 0;
}
複製代碼

運行此程序之前,用VC6.0建立一個二進製文件test放在工程目錄下,然後輸入數據"23 13 0E 1A 35"。保存完畢後再執行此程序,執行結果為:

23
13
0E
1A
35
Press any key to continue

但是若將打開方式改成"rt",則執行結果為:

23
13
0E
Press any key to continue

之所以出現這種原因,在上麵已經提到,就是在以文本方式打開文件時,若讀取到ASCII碼為26的字符,則會停止讀取,默認文件內容已經結束。但是以二進製方式打開文件則不會出現這種情況,會將文件中所有的內容原樣輸出(注意這種區別隻在windows下存在,在unix下兩種方式打開文件程序的執行結果是相同的即會原樣輸出文件中所有的內容

最後更新:2017-04-02 15:15:02

  上一篇:go PHP比你想象的好得多
  下一篇:go 我的程序裏《我的歌聲裏》程序員版