重溫C語言(7)之文件輸入與輸出

https://mp.weixin.qq.com/s/obcOxx9e6edRHcKYIh4YLQ

[toc]

文件

File (文件)是硬盤磁盤上的被命名的存儲空間。
C 把文件看作是一系列的字節,每個字節都能被單獨讀取。

所有文件的內容都是以二進制存儲的。文本文件以二進制編碼的字符比如ASCLL或Unicode 存儲,二進制文件以機器語言代碼或樹值數據或圖片或音樂編碼存儲。

exit()函數關閉搜有打開的文件並結束程序,exit(0)exit(EXIT_SUCCESS) 表示成功結束程序, eixt(EXIT_FAILURE) 表示結束程序失敗。

return 會把控制權交給上級函數,直到最初函數。

fopen()

fopen() 函數用於打開文件,第一個參數是地址,第二個參數是打開文件的模式。返回文件指針(指向FILE的指針)。

模式有如下幾個:

模式 含義
"r" 以只讀模式打開文件
"w" 寫模式,把文件長度截取爲0即文件內容被刪除,文件不存在則創建新的
"a" 寫模式,在文件末尾添加內容,文件不存在則創建新的
"r+" 更新模式,可以讀寫文件
"w+" 更新模式,文件長度截取爲0,文件不存在則創建新的
"a+" 更新模式,只允許在文件末尾添加內容,文件不存在則創建新的,這個模式可以讀取整個文件
"rb","wb","ab","rb+","r+b","wb+","w+b","ab+","a+b" 更新模式,以二進制模式打開文件
"wx","wbx","w+x","wb+x,"w+bx" (C11)類似非x模式,但是如果文件已存在或以獨佔模式打開文件,則打開文件失敗

帶x字母的寫模式,即使fopen()操作失敗,原文件的內容也不會被刪除。第二,如果環境允許,x模式的獨佔特性使得其他程序或線程無法訪問正在被打開的文件。

getc()

getc(文件指針) 從文件指針指向的文件獲取一個字符。

putc()

getc(字符,文件指針) 把字符放入文件指針指向的文件中。

fclose()

fclose(文件指針) 關閉文件指針指向的文件,關閉成功返回 0, 否則返回 EOF,必要的時候刷新緩衝區。

示例(1):

// 預編譯器,把stdio.h文件中的所有內容都輸入該行所在的位置, stdio.h 包含了供編譯器使用的輸入輸出函數
#include <stdio.h> // <- C 預處理指令


int main() { // <- 函數體開始


    int ch;
    FILE * fp = fopen("../test/test.txt", "r");
    FILE * fpout = fopen("../test/testout.txt", "w");
    ch = getc(fp);
    while ((ch = getc(fp)) != EOF) { // 得到一個輸入,判斷是否是文件末尾
        putchar(ch);
        putc(ch, fpout);
    }

    if(fclose(fp) != 0){

        printf("關閉test文件失敗\n");
    }
    if(fclose(fpout) != 0){
        printf("關閉testout文件失敗\n");
    }

    return 0; // <- 函數體結束
}

fprintf()

printf() 類似,但是又多了一個參數,第一個參數是個文件指針,例如:

fprintf(stderr, "error %s", "error");
fprintf(stdout, "error %s", "error");

stderr 指針用於把錯誤信息發送至標準錯誤。
stdout 指針用於把信息發送至標準輸出。

fprintf(文件指針, "msg %s", "msg");

把信息寫入到 文件指針指向的文件中。

fscanf()

scanf() 類似,但是又多了一個參數,第一個參數是個文件指針,例如:

char words[41];
fscanf(stdin, "%40s", words);

從標準輸入讀取信息到 words 中。

fscanf(文件指針, "%s", words);

讀取文件指針指向的文件中的單詞到 words 中。

rewind()

rewind(文件指針) 使程序返回到文件開始處。

fgets()

fgets(字符指針, 字符串大小, 文件指針)

會讀取到第一個換行符,或者文件末尾,或者指定字符串大小個字符。
fgets()會在字符串末尾加上一個空字符。

fputs()

fputs(字符串地址, 文件指針)

把字符串寫入到指定文件中。

fseek() 和 ftell()

fseek(文件指針, 偏移量, SEEK_SET|SEEK_CUR|SEEK_END) 可以在打開的文件中移動到任意字節處。
ftell() 返回 long 類型值表示文件的當前位置。

  • SEEK_SET 文件開始處;
  • SEEK_CUR 當前位置;
  • SEEK_END 文件末尾;
  long last;
    FILE * fp = fopen("../test/test.txt", "rb");
    // 定位到文件末尾
    fseek(fp, 0, SEEK_END);
    int ch;
    last = ftell(fp);
    for (long i = 1; i <= last; ++i) {
        // 定位到文件末尾的前 i 位
        fseek(fp, -i, SEEK_END);
        ch = getc(fp);
        putchar(ch);
    }
    fclose(fp);

fgetpos() 和 fsetpos()

突破 fseek() 和 ftell() 的 long 限制。

fpos_t: 文件定位類型, 它的對象或變量可以指定文件中的一個位置。

int fgetpos(FILE * __restrict, fpos_t * restrict pos); 成功返回0,否則非0,獲取當前位置並存入pos, pos 指向的是 fpos_t 類型值,描述文件當前位置到文件開頭的字節數字。

int fsetpos(FILE *, const fpos_t * restrict pos); 成功返回0,失敗返回非0,設置文件指針指向的位置。

ungetc()

int ungetc(int c, FILE *fp);函數把c指定的字符放回輸入流中。如果把一個字符放回輸入流,下次調用標準輸入函數時將讀取該字符。

fflush()

int fflush(FILE *fp); 刷新緩衝區,調用fflush()函數引起輸出緩衝區中所有的未寫入數據被髮送到fp指定的輸出文件。

setvbuf()

在打開文件後且未對流進行其他操作之前,調用它創建緩衝區。
int setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size);創建了一個供標準I/O函數替換使用的緩衝區, 成功返回0,否則非0.
fp: 待處理的流;
buf: 待使用的存儲區, 如果是 NULL 會自動創建;
mode: _IOFBF 完全緩衝區即緩衝區慢點時候刷新,_IONBF無緩衝 ;
size: size_t 派生整數類型,數組的大小;

fwrite()

函數用於二進制形式的數據寫入處理。
size_t fwrite(const void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream); 把二進制數據寫入文件, 返回成功寫入項目的數量;

size_tunsigned int, 是 sizeof 運算符返回的類型;size表示待寫入數據塊的大小(以字節爲單位);nmemb表示待寫入數據塊的數量;
例如: 保存 含有10個 double類型值的數組

double a[10];
fwrite(a, sizeof(double), 10, fp);

fread()

函數用於二進制形式的數據寫入處理。
size_t fread(void * __restrict __ptr, size_t __size, size_t __nitems, FILE * __restrict __stream); 讀取被 fwrite() 寫入文件的數據, 返回成功讀取項的數量;

例如: 讀取含有 10 個 double 類型值的數組,並拷貝到 oa 中,

double oa[10];
fread(oa, sizeof(double), 10, fp);

feof() ferror()

int  feof(FILE *);
int  ferror(FILE *);

文件末尾時,函數返回 EOF,但是文件出錯也返回 EOF,這兩個函數就是來判斷這兩個情景的。
當上一次輸入調用檢測到文件結尾時,feof()函數返回一個非零值,否則返回0。當讀或寫出現錯誤,ferror()函數返回一個非零值,否則返回0。

示例

獲取文件名

char * s_gets(char * st, int n{
    char * ret_val;
    char * find;
    ret_val = fgets(st, n, stdin);
    if(ret_val){
        find = strchr(st, '\n');//查找換行符  
        if(find)    //如果地址不是NULL,
            *find='\0';     //在此處放置一個空字符
        else
            while(getchar() != '\n')
                continue;
     }

    return ret_val;
}

拷貝

記得要給文件創建緩衝區

if(setvbuf( fa, NULL, _IOFBF, BUFSIZE) != 0){
    fputs("無法創建緩衝區\n", stderr);
    exit(EXIT_FAILURE);
}
void append(FILE * source, FILE * dest){
    size_t bytes;
    static char temp[BUFSIZE];//只分配一次
    while((bytes = fread(temp, sizeof(char), BUFSIZE, source)) > 0)
    fwrite(temp, sizeof(char), bytes, dest);
}


總結

當輸入函數發現已讀完緩衝區中的所有字符時,會請求把下一個緩衝大小的數據塊從文件拷貝到該緩衝區中。以這種方式,輸入函數可以讀取文件中的所有內容,直到文件結尾。函數在讀取緩衝區中的最後一個字符後,把結尾指示器設置爲真。於是,下一次被調用的輸入函數將返回EOF。輸出函數以類似的方式把數據寫入緩衝區。當緩衝區被填滿時,數據將被拷貝至文件中。

fopen()函數爲標準I/O打開一個文件,並創建一個用於存儲文件和緩衝區信息的結構。
feof()和ferror()函數報告I/O操作失敗的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章