14-C語言文件操作

文件基本概念

  • 文件分類

    • 文本文件

      • 以ASCII碼格式存放,一個字節(jié)存放一個字符.
    • 二進(jìn)制文件

      • 以二進(jìn)制存儲的
  • 文本文件和二進(jìn)制文件的區(qū)別

    • 1.存儲步驟不同
      • 文本文件在存儲的時候,會先查詢需要存儲數(shù)據(jù)的ASCII碼, 然后再將對應(yīng)的ASCII 碼轉(zhuǎn)換為二進(jìn)制,然后再存儲;
    • 2.從存儲步驟來看,文本文件需要縣查找再存儲, 所以效率會低一些
    • 3.從內(nèi)存上的表現(xiàn), 文本文件會更占用內(nèi)存
  • 注意點:
    • 任何的文本編輯器在打開文件的時候,都會以某種編碼方式去解碼存儲的數(shù)據(jù)
    • 而文本編輯器默認(rèn)的解碼方式就是ASCII碼解碼

文件的打開和關(guān)閉

  • fputc/ fputs/ fgetc/ fgets 這些函數(shù)都是用于操作文本文件的;
  • fwrite / fread 這兩個函數(shù)就是用于操作二進(jìn)制文件的
  • 也就是說:
    • fputc/ fputs/ fgetc/ fgets保存的都是 ASCII碼
    • fwrite / fread 保存的是二進(jìn)制

fopen()函數(shù)

  • fopen函數(shù)返回的FILE * 是一個指向結(jié)構(gòu)體的指針;
  • FILE *并不是打開的那個文件, 而是一個結(jié)構(gòu)體,這個結(jié)構(gòu)體中描述了被打開文件在緩沖區(qū)中的各種狀態(tài)
  • 函數(shù)的聲明: FILE * fopen ( const char * filename, const char * mode );
    • 兩個參數(shù)都是傳入字符串
    • 第一個參數(shù): 需要打開的文件的名稱
    • 第二個參數(shù): 打開文件的模式
    • 返回值: 如果打開文件成功, 會返回文件的句柄, 如果打開失敗會返回NULL
    • 模式的對應(yīng)取值
    • r 讀取文件
      • 文件不存在會報錯,文件存在就打開
      • 只能讀不能寫
      FILE *fp = fopen("abc.txt", "r");
      if(fp == NULL){
          printf("打開失敗\n");
      }
      
    • w 寫入文件
      • 文件不存在會自動創(chuàng)建, 文件存在會直接打開
      • 只能寫不能讀
      FILE *fp = fopen("abc", "r");
      if(fp == NULL){
          printf("打開失敗");
      }
      
    • r+ 讀取和寫入文件
      • 文件不存在會報錯,文件存在就會打開
      • 既可以讀又可以寫
      FILE *fp = fopen("abc.txt", "r+");
      if(fp == NULL){
          printf("打開失敗");
      }
      
    • w+ 讀取和寫入文件(重點)
      • 文件不存在會自動創(chuàng)建, 文件存在會直接打開
      • 既可以讀也可以寫
      FILE *fp = fopen("abc.txt", "w+");
      if(fp == NULL){
          printf("打開失敗\n");
      }
      
    • a 追加寫入文件
      • 文件不存在會自動創(chuàng)建, 文件存儲會直接打開
      • 只能在原有數(shù)據(jù)的基礎(chǔ)上追加
      FILE *fp = fopen("abc.txt", "a");
      if(fp == NULL){
          printf("打開失敗\n");
      }
      
    • a+ 追加寫入文件,并且可以讀取(重點)
      • 文件不存在會自動創(chuàng)建, 文件存在會直接打開
      • 可以在原有數(shù)據(jù)的基礎(chǔ)上追加, 并且還可以讀取數(shù)據(jù)
      FILE *fp = fopen("abc.txt", "a+");
      if(fp == NULL){
          printf("打開失敗\n");
      }
      

fclose()函數(shù)

  • 格式: fclose(fp);
    • 第一個參數(shù): 需要關(guān)閉的文件句柄
    • 返回值: int 成功返回0, 失敗返回 EOF(-1);
  • 一次寫入一個字符 (fputc函數(shù))
  • fputc就是寫入一個字符
    • fputc是以文本文件的形式保存數(shù)據(jù)
    • 格式: int fputc (int ch, FILE * stream );
    • 第一個參數(shù): 需要寫入到文件的字符
    • 第二個參數(shù): 已經(jīng)打開文件句柄;
    • 返回值:寫入成功,返回寫入成功的字符, 如果失敗, 返回 EOF
    • EOF 是文件結(jié)束的標(biāo)識,本質(zhì)上就是-1;
    FILE *fp = fopen("abc.txt", "w");
    int res = fputc('a', fp);
    printf("res = %i\n", res);
    
    // 關(guān)閉打開的文件
    fclose(fp);
    

一次讀取一個字符(fgetc()函數(shù))

  • int fgetc ( FILE * stream );
    • 第一個參數(shù): 被讀取的文件的 文件句柄
    • 返回值:當(dāng)前獲取到的字符, 如果獲取失敗就會返回 EOF
    FILE *fp = fopen("abc.txt", "w+");
    fputc('a',fp);
    fputc('b',fp);
    fputc('c',fp);
    fputc('d',fp);
    
    // 每次操作完文件,文件的指針都會向后移動
    // 將文件指針重新只想一個流的開頭
    rewind(fp);
    // fgetc 被讀取的文件的 文件句柄
    char ch ;
    while((ch = fgetc(fp)) != EOF){
        printf("ch = %c\n", ch);
    }
    
    

文件末尾的判斷(feof()函數(shù))

  • feof()函數(shù)(了解一下)

    • 返回值為0, 沒有讀到文件末尾
    • 如果返回非0, 代表讀到了文件末尾
    #include <stdio.h>
    
    int main()
    {
        FILE *fp = fopen("abc.txt", "w+");
        fputc('a',fp);
        fputc('b',fp);
        fputc('c',fp);
        fputc('d',fp);
    
        // 將文件指針重新只想一個流的開頭
        rewind(fp);
        
        // 按照下列的寫法, 會多讀取一個字符
        // 原因就是feof函數(shù)在判斷文件指針時, 指針還沒有移動
        // 只有寫入或者讀取過來指針才會移動
        
        char ch ;
    //    while(!feof(fp)){
    //        ch = fgetc(fp);
    //        printf("ch = %c\n", ch);
    //    }
    
        // 所以在使用feof函數(shù)的時候, 一定要先取, 然后再判斷feof
        // 否者會多取一個
        while((ch = fgetc(fp)) && !feof(fp)){
            printf("ch = %c\n", ch);
        }
    
        return 0;
    }
    
    
  • 注意點:在使用feof函數(shù)的時候,一定要先取 ,然后再判斷Feof, 否則會奪取一個

  • 定義函數(shù), 實現(xiàn)文件的加密和解碼

#include <stdio.h>
void encode(char *name, char *newName, int code);
int main()
{
    // 編碼
    //encode("abc.txt", "encode.txt", 6);
    // 解碼
    encode("encode.txt", "decode.txt", 6);
    return 0;
}


void encode(char *name, char *newName, int code){
    // 打開一個需要加密的文件
    FILE *fr = fopen(name, "r+");
    // 打開需要寫入加密內(nèi)容的文件
    FILE *fw = fopen(newName, "w+");
    // 不斷的讀  不斷的加密 不斷的寫入
    char ch = EOF;
    while((ch = fgetc(fr)) != EOF){
        ch = ch ^ code;
        fputc(ch, fw);
    }
    // 關(guān)閉已經(jīng)打開的文件
    fclose(fr);
    fclose(fw);
}



一次性寫入一行數(shù)據(jù)(fputs()函數(shù))

  • fputs()函數(shù)可以一次寫入一堆字符
  • 格式: fputs(const char * restrict _Str,FILE * restrict _File);
    • 第一個參數(shù): 需要寫入的數(shù)據(jù)
    • 第二個參數(shù): 寫入到那個文件的文件句柄
  • 注意點: 不會再寫入字符的后面自動添加\n
// 打開一個文件
FILE *fp = fopen("abc.txt", "w+");
// 一次寫入一堆函數(shù):需要自己添加換行 \n
fputs("www.baidu.com\n", fp);
fputs("www.taobao.com\n", fp);
// 關(guān)閉打開的文件
fclose(fp);

一次性讀取一行數(shù)據(jù)(fgets()函數(shù))

  • fgets()函數(shù) 格式: fgets(char * restrict _Buf,int _MaxCount,FILE * restrict _File);

    • 第一個參數(shù): 讀取出來的數(shù)據(jù)會放到這個參數(shù)的變量中
    • 第二個參數(shù): 需要讀取多少個字節(jié)的數(shù)據(jù)
    • 第三個參數(shù): 被讀取文件的句柄
    • 注意點: 雖然告訴系統(tǒng)需要讀取1024個字符,但是只要遇到\n, fgets函數(shù)就會自動終止讀取
    FILE *fp = fopen("abc.txt", "r+");
    char buf[1024];
    fgets(buf, 1024, fp);
    printf("buf = %s\n", buf);
    // 關(guān)閉打開的文件
    fclose(fp);
    
  • 注意點:

    • 遇到\n自動結(jié)束,并且\n 也會被讀取進(jìn)來
    • maxCount 指定多睡不一定會讀取多少, 讀取到\n會自動停止讀取
    • 最多只能讀取 maxCount - 1 個字符, 會在最后自動添加 \0
    • 遇到EOF也會自動停止讀取
    #include <stdio.h>
    
    int main()
    {
        FILE *fp = fopen("abc.txt", "r+");
        char buf[1024];
    
        /*
         * abc.txt  : hello world
         *            www.baidu.com
        */
        // 每次只能讀取n-1個字符, 會在末尾自動添加\0
        fgets(buf, 4, fp);
        printf("buf = %s\n", buf);  // hel
    
        fgets(buf, 1024, fp);
        printf("buf = %s\n", buf);
    
        // 關(guān)閉打開的文件
        fclose(fp);
    
        return 0;
    }
    
    
  • 遍歷寫法

// 推薦寫法
    while(fgets(buf, 1024, fp) != NULL){
        printf("buf = %s\n", buf);
    }

// 不推薦寫法
    while(fgets(buf, 1024, fp) && !feof(fp)){
        
        printf("buf = %s\n", buf);
    }

一次性寫入一塊數(shù)據(jù)(fwrite()函數(shù))

  • 格式: fwrite(const void * restrict _Str,size_t _Size,size_t _Count,FILE * restrict _File);
    • 第一個參數(shù): 需要寫入文件的數(shù)據(jù)地址
    • 第二個參數(shù): 每次寫入多少個字節(jié)
    • 第三個參數(shù): 需要寫入多少次
    • 第四個參數(shù): 寫入到上面地方
    • 返回值: 寫入了多少次就返回多少, 出錯或文件結(jié)束, 返回 0;
FILE *fp = fopen("abc.txt", "w+");
int ages[] = {1, 3, 5};
printf("sizeof(ages) = %i\n", sizeof(ages));
fwrite(&ages, sizeof(ages), 1, fp);
  • 注意點:
    • 一般情況下, 寫入一塊數(shù)據(jù),每次寫入多少個字節(jié)可以寫大一點, 而寫入多少次會寫小一點;
    • 由于fwrite是以二進(jìn)制的形式寫入文件的, 所以和以文件的寫入不同, fwrite函數(shù)會忽略 \0 \n等內(nèi)容;
FILE *fp = fopen("abc.txt", "w+");
char *str = "hello\0world";
// fputs是以文本文件的形式存儲, 存儲的是ASCII
// 注意點: 如果利用fputs寫入字符串, 遇到\0會停止寫入
//    fputs(str, fp);
// 注意點: 在二進(jìn)制中是沒有\(zhòng)n \0這些概念的, 寫入的時候不會受到\0 \n的影響
fwrite(str, 9, 1, fp);

一次性讀取一塊數(shù)據(jù)(fread()函數(shù))

  • 格式: fread(void * restrict _DstBuf,size_t _ElementSize,size_t _Count,FILE * restrict _File);
    • 第一個參數(shù): 讀取的數(shù)據(jù)存儲到哪
    • 第二個參數(shù): 一次讀取多少個字節(jié)
    • 第三個參數(shù): 讀取多少次
    • 第四個參數(shù): 從什么地方讀取
    • 返回值: 讀取了多少就返回多少, 如果返回0 代表讀取錯誤
FILE *fp = fopen("abc.txt", "w+");
// abc.txt :  hello world
char buf[1024] = {0};
// fp對應(yīng)的文件中讀取1024次,每次讀取1個字節(jié), 將讀取的內(nèi)容放到buf中
fread(buf, 1, 1024, fp);
printf("buf = %s\n", buf);
  • 注意點:
    • fread(buf, 1, 1024, fp); 雖然告訴系統(tǒng)需要讀取1024次,但是只要讀取到EOF就不會讀取了
    • 每次讀取多少個字節(jié), 一定要按照存儲的數(shù)據(jù)類型占用的內(nèi)存大小來讀取, 不要寫過大的值
FILE *fp = fopen("abc.txt", "wb+");
char *str1 = "123456";
fwrite(str1, sizeof(char), strlen(str1), fp);
rewind(fp);
char buf[1024] = {0};
while(fread(buf, 1, 1024, fp) > 0){
    printf("buf = %s\n", buf);
}

讀寫結(jié)構(gòu)體

  • 讀單個結(jié)構(gòu)體
#include <stdio.h>
typedef struct person{
    char *name;
    int age;
    double height;
} Person;
int main()
{
//    // 寫入一個結(jié)構(gòu)體
//    Person p = {"www", 18, 1.78};
//    FILE *fp = fopen("abc.txt", "wb+");
//    fwrite(&p, sizeof(Person), 1, fp);
//    // 關(guān)閉文件
//    fclose(fp);

    // 讀一個結(jié)構(gòu)體
    FILE *fp = fopen("abc.txt", "rb+");
    Person p;
    fread(&p, sizeof(Person), 1, fp);
    printf("name = %s\n", p.name);
    printf("age = %i\n", p.age);
    printf("height = %lf\n", p.height);
    // 關(guān)閉文件
    fclose(fp);
    return 0;
}

  • 讀寫結(jié)構(gòu)體數(shù)組
#include <stdio.h>
typedef struct person{
    char name[8];
    int age;
    double height;
} Person;
int main()
{

//        // 寫入一個結(jié)構(gòu)體數(shù)組
//        Person ps[3] = {
//            {"www", 38, 1.38},
//            {"baidu", 18, 1.78},
//            {"com", 98, 1.58},
//        };
//        FILE *fp = fopen("abc.txt", "wb+");
//        fwrite(&ps, sizeof(ps), 1, fp);
//        // 關(guān)閉文件
//        fclose(fp);



        // 讀一個結(jié)構(gòu)體數(shù)組
        FILE *fp = fopen("abc.txt", "rb+");
        Person ps[3];
        fread(&ps, sizeof(Person), 3, fp);
        for(int i = 0; i< 3; i++){
            Person p = ps[i];
            printf("name = %s\n", p.name);
            printf("age = %i\n", p.age);
            printf("height = %lf\n", p.height);
            printf("----------\n");
        }
         // 關(guān)閉文件
        fclose(fp);


    return 0;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖茄螃,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡绰寞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門铣口,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滤钱,“玉大人,你說我怎么就攤上這事脑题〖祝” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵叔遂,是天一觀的道長他炊。 經(jīng)常有香客問我争剿,道長,這世上最難降的妖魔是什么痊末? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任蚕苇,我火速辦了婚禮,結(jié)果婚禮上凿叠,老公的妹妹穿的比我還像新娘涩笤。我一直安慰自己,他們只是感情好盒件,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布蹬碧。 她就那樣靜靜地躺著,像睡著了一般炒刁。 火紅的嫁衣襯著肌膚如雪锰茉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天切心,我揣著相機(jī)與錄音飒筑,去河邊找鬼。 笑死绽昏,一個胖子當(dāng)著我的面吹牛协屡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播全谤,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼肤晓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了认然?” 一聲冷哼從身側(cè)響起补憾,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卷员,沒想到半個月后盈匾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡毕骡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年削饵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片未巫。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡窿撬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叙凡,到底是詐尸還是另有隱情劈伴,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布握爷,位于F島的核電站跛璧,受9級特大地震影響苏遥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赡模,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望师抄。 院中可真熱鬧漓柑,春花似錦、人聲如沸叨吮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茶鉴。三九已至锋玲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間涵叮,已是汗流浹背惭蹂。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留割粮,地道東北人盾碗。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像舀瓢,于是被迫代替她去往敵國和親廷雅。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容