日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

一文詳解C語言中文件相關函數的使用_C 語言

作者:蔣靈瑜的流水賬 ? 更新時間: 2022-09-13 編程語言

一、文件和流

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("%s\n", 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("%s\n", 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("%s\n", strerror(errno));
        exit(-1);
    }
    printf("%c\n", fgetc(pf));//輸入,也可以寫一個循環讀取
    printf("%c\n", fgetc(pf));
    printf("%c\n", fgetc(pf));
    printf("%c\n", fgetc(pf));
    printf("%c\n", 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個,最后一個補了\0

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編譯系統決定的。

原文鏈接:https://blog.csdn.net/gfdxx/article/details/125884458

欄目分類
最近更新