首頁 > 軟體

一文詳解C語言中檔案相關函數的使用

2022-07-20 18:03:07

一、檔案和流

1、程式檔案

包括源程式檔案(字尾為.c)

目標檔案(windows環境字尾為.obj)

可執行程式(windows環境 字尾為.exe)

2、資料檔案

檔案的內容不一定是程式,而是程式執行時讀寫的資料,比如程式執行需要從中讀取資料的檔案, 或者輸出內容的檔案。

3、流

任何一個C程式,執行起來就會預設開啟3個流

1、FILE* stdin(標準輸入流,鍵盤)

2、FILE* stdout(標準輸出流,顯示器)

3、FILE* stderr(標準錯誤流,顯示器)

流可以理解為輸入/輸出緩衝區

二、檔案組成

每個被使用的檔案都在記憶體中開闢了一個相應的檔案資訊區,用來存放檔案的相關資訊(如檔案的名 字,檔案狀態及檔案當前的位置等)。這些資訊是儲存在一個結構體變數中的。該結構體型別是由系統宣告的,取名FILE

FILE*就是檔案指標型別,可以通過檔案指標找到它指向的檔案資訊區(FILE型別的結構體),檔案資訊區用於維護一個檔案(每個檔案都是獨立的檔案資訊區)

三、檔案的開啟和關閉

1、檔案的開啟fopen

filename是檔名

mode是檔案開啟方式

檔案開啟方式含義如果指定檔案不存在
“r”(唯讀)為了輸入資料,開啟一個已經存在的文字檔案出錯
“w”(只寫)為了輸出資料,開啟一個文字檔案建立一個新的檔案
“a”(追加)向文字檔案尾新增資料建立一個新的檔案
“rb”(唯讀)為了輸入資料,開啟一個二進位制檔案出錯
“wb”(只寫)為了輸出資料,開啟一個二進位制檔案建立一個新的檔案
“ab”(追加)向一個二進位制檔案尾新增資料出錯
“r+”(讀寫)為了讀和寫,開啟一個文字檔案出錯
“w+”(讀寫)為了讀和寫,新建一個文字檔案建立一個新的檔案
“a+”(讀寫)開啟一個檔案,在檔案尾進行讀寫建立一個新的檔案
“rb+”(讀寫)為了讀和寫開啟一個二進位制檔案出錯
“wb+”(讀寫)為了讀和寫,新建一個新的二進位制檔案建立一個新的檔案
“ab+”(讀寫)開啟一個二進位制檔案,在檔案尾進行讀和寫建立一個新的檔案

2、檔案關閉fclose

stream是檔案指標,檔案使用完後一定要fclose關閉,並把檔案指標置空。(用起來像free)

int main()
{
    FILE* pf = fopen("text.txt", "r");//檔案路徑可以是相對路徑或絕對路徑
    if (pf == NULL)
    {
        printf("%sn", strerror(errno));
        exit(-1);
    }
    fclose(pf);//不關閉檔案可能會造成資料丟失
    pf = NULL;
    return 0;
}

四、檔案的順序讀寫

字元輸入函數fgetc所有輸入流
字元輸出函數fputc所有輸出流
文字行輸入函數fgets所有輸入流
文字行輸出函數fputs所有輸出流
格式化輸入函數fscanf所有輸入流
格式化輸出函數fprintf所有輸出流
二進位制輸入fread檔案
二進位制輸出fread檔案

1、使用fputc和fgetc寫入/讀取單個字元

寫入單個字元到檔案

character:要寫入的字元

stream:指向輸出流 FILE 物件的指標。

int main()
{
    FILE* pf = fopen("text.txt", "w");//檔案路徑可以是相對路徑或絕對路徑
    if (pf == NULL)
    {
        printf("%sn", strerror(errno));
        //perror("fopen");//void perror ( const char * str )用來將上一個函數發生錯誤的原因輸出到標準裝置(stderr)
        exit(-1);
    }
    for (char i = 'a'; i <= 'z'; i++)
    {
        fputc(i, pf);//輸出
    }
    fclose(pf);
    pf = NULL;
}

讀取檔案中的單個字元

stream:指向輸入流 FILE 物件的指標。

int main()
{
    pf = fopen("text.txt", "r");//檔案路徑可以是相對路徑或絕對路徑
    if (pf == NULL)
    {
        printf("%sn", strerror(errno));
        exit(-1);
    }
    printf("%cn", fgetc(pf));//輸入,也可以寫一個迴圈讀取
    printf("%cn", fgetc(pf));
    printf("%cn", fgetc(pf));
    printf("%cn", fgetc(pf));
    printf("%cn", fgetc(pf));
    fclose(pf);
    pf = NULL;
    return 0;
}

2、使用fputs和fgets寫入/讀取一串字元

寫入一串字元到檔案

str:要寫入的字串的地址

stream:指向輸出流 FILE 物件的指標。

int main()
{
    FILE* pf = fopen("text.txt", "w");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    char arr[] = "abcde";//text.txt檔案被寫入abcde
    fputs(arr, pf);
    fclose(pf);
    pf = NULL;
    return 0;
}

讀取檔案中num個字元

str:讀到的字串放到str指向的空間裡去

num:讀取的字串個數

stream:指向輸入流 FILE 物件的指標。

讀取成功:返回str的地址

讀取失敗或錯誤:返回空指標

監視發現,我們從檔案中讀取5個字元,實際唯讀了4個,最後一個補了

3、使用fprintf和fscanf按照指定的格式寫入/讀取

stream:指向輸出流 FILE 物件的指標。

後續引數使用方法與printf一樣

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { "zhangsan",1510,66.5f };
    FILE* pf = fopen("text.txt", "w");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fprintf(pf, "%s %d %f", s.name, s.tele, s.scores);//列印到txt檔案
    fprintf(stdout, "%s %d %f", s.name, s.tele, s.scores);//列印到螢幕
    fclose(pf);
    pf = NULL;
    return 0;
}

stream:指向輸入流 FILE 物件的指標。

後續引數使用方法和scanf一樣

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { 0 };
    FILE* pf = fopen("text.txt", "r");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fscanf(pf, "%s %d %f", s.name, &s.tele, &s.scores);//將檔案中的內容讀取到結構體中
    printf("%s %d %f", s.name, s.tele, s.scores);
    fclose(pf);
    pf = NULL;
    return 0;
}

4、使用fwrite和fread按照二進位制的方式寫入/讀取

ptr:從ptr指向的當前位置開始寫入

size:每個元素的大小

count:要寫入的元素個數

stream:指向輸出流 FILE 物件的指標。

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { "zhangsan",1510,66.5f };
    FILE* pf = fopen("text.txt", "wb");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fwrite(&s, sizeof(struct S), 1, pf);
    fclose(pf);
    pf = NULL;
    return 0;
}

fread引數和fwrite一樣

ptr:從ptr指向的當前位置開始讀取

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { 0 };
    FILE* pf = fopen("text.txt", "rb");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fread(&s, sizeof(struct S), 1, pf);
    printf("%s %d %f", s.name, s.tele, s.scores);
    fclose(pf);
    pf = NULL;
    return 0;
}

5、使用sprintf和sscanf將格式化資料和字串互相轉換(檔案無關)

將格式化資料轉換為字串

str:將格式化資料放到目標地址

後續引數和使用方式和printf一樣

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { "zhangsan",1510,66.5f };
    char arr[60]={0};
    sprintf(arr, "%s %d %f", s.name, s.tele, s.scores);
    printf("%s", arr);
    return 0;
}

將字串轉換為格式化資料

s:指向字串的指標

後續引數和使用方式和scanf一樣

struct S
{
    char name[20];
    int tele;
    float scores;
};
int main()
{
    struct S s = { 0 };
    char arr[60]={ "zhangsan 1510 66.5f" };
    sscanf(arr, "%s %d %f", s.name, &s.tele,&s.scores);
    printf("%s %d %f", s.name,s.tele,s.scores );
    return 0;
}

五、檔案的隨機讀寫

1、fseek(指定檔案指標的位置)

注意:每次檔案讀取完畢後,檔案指標++

stream:指向標識流的 FILE 物件的指標

offset:指標偏移量

origin:指標起始點,如下圖:

SEEK_SET檔案開頭
SEEK_CUR檔案指標的當前所處的位置
SEEK_END檔案結尾
int main()
{
    FILE* pf = fopen("text.txt", "r+");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fputs("abcde", pf);
    fseek(pf, 2, SEEK_SET);
    int ch = fgetc(pf);//該語句執行完畢後,指標++,指向d
    printf("%c ", ch);//列印c
 
    fseek(pf, 0, SEEK_CUR);
    ch = fgetc(pf); //該語句執行完畢後,指標++,指向e
    printf("%c ", ch);//列印d
 
    fseek(pf, -1, SEEK_END);//這裡SEEK_END是指向e的後一個
    ch = fgetc(pf);//該語句執行完畢後,指標++,指向e的後一個
    printf("%c ", ch);//列印e
    fclose(pf);
    pf = NULL;
    return 0;
}

2、ftell(求檔案指標與起始位置的偏移量)

int main()
{
    FILE* pf = fopen("text.txt", "r+");
    if (pf == NULL)
    {
        perror("fopen:");
        exit(-1);
    }
    fputs("abcde", pf);
    fseek(pf, -1, SEEK_END);//這裡SEEK_END是指向e的後一個
    int ch = fgetc(pf);//該語句執行完畢後,指標++,指向e的後一個
    printf("%c ", ch);//列印e
    printf("%d", ftell(pf));//列印5,當前指標在e的後一個,相對於a相差5
    fclose(pf);
    pf = NULL;
    return 0;
}

3、rewind(讓檔案指標回到起始位置)

六、文字檔案和二進位制檔案的區別

資料在記憶體中以二進位制的形式儲存,如果不加轉換的輸出到外存,就是二進位制檔案。

如果要求在外存上以ASCII碼的形式儲存,則需要在儲存前轉換。以ASCII字元的形式儲存的檔案就是文字檔案。 字元一律以ASCII形式儲存,數值型資料既可以用ASCII形式儲存,也可以使用二進位制形式儲存。

七、檔案讀取結束的標誌

文字檔案讀取是否結束,fgetc判斷返回值是否為 EOF . fgets判斷返回值是否為 NULL

二進位制檔案的讀取結束判斷,判斷返回值是否小於實際要讀的個數。 例如: fread判斷返回值是否小於還是等於實際要讀的個數。

feof:判斷檔案是否讀到末尾而結束,返回值為真,就是讀到了檔案結束

ferror:判斷檔案是否讀取錯誤而結束,返回值為真,就是檔案讀取遇到了錯誤

八、檔案緩衝區

ANSIC 標準採用“緩衝檔案系統”處理的資料檔案的,所謂緩衝檔案系統是指系統自動地在記憶體中為程式中每一個正在使用的檔案開闢一塊“檔案緩衝區”。

從記憶體向磁碟輸出資料會先送到記憶體中的緩衝區,裝滿緩衝區後才一起送到磁碟上。

如果從磁碟向計算機讀入資料,則從磁碟檔案中讀取資料輸入到記憶體緩衝區(充滿緩衝區),然後再從緩衝區逐個地將資料送到程式資料區(程式變數等)。緩衝區的大小根據C編譯系統決定的。

到此這篇關於一文詳解C語言中檔案相關函數的使用的文章就介紹到這了,更多相關C語言檔案相關函數內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com