C提高6—文件的基本概念

以下內容爲本人看“傳智播客”C++基礎教程完整版視頻所做的筆記

文件的基本概念

按文件的邏輯結構:

  • 記錄文件:由具有一定結構的記錄組成(定長和不定長)
  • 流式文件:由一個個字符(字節)數據順序組成

按存儲介質:

  • 普通文件:存儲介質文件(磁盤、磁帶等)
  • 設備文件:非存儲介質(鍵盤、顯示器、打印機等)

按數據的組織形式:

  • 文本文件: ASCII文件,每個字節存放一個字符的ASCII碼
  • 二進制文件:數據按其在內存中的存儲形式原樣存放
    寫文件
int main()
{
    errno_t err;
    char buf[] = "this is a test\n";
    FILE *fp;
    err = fopen_s(&fp, "./test.txt", "w+");
    //"w+",寫讀方式打開,如果文件不存在,則創建;如果文件存在,清空內容,再寫
    fputs(buf, fp);



    printf("\n");
    system("pause");
    return 0;
}

在以下路徑中生成文件“test.txt”
這裏寫圖片描述

流概念

  流是一個動態的概念,可以將一個字節形象地比喻成一滴水,字節在設備、文件和程序之間的傳輸就是流,類似於水在管道中的傳輸,可以看出,流是對輸入輸出源的一種抽象,也是對傳輸信息的一種抽象。通過對輸入輸出源的抽象,屏蔽了設備之間的差異,使程序員能以一種通用的方式進行存儲操作,通過對傳輸信息的抽象,使得所有信息都轉化爲字節流的形式傳輸,信息解讀的過程與傳輸過程分離。
  C語言中,I/O操作可以簡單地看作是從程序移進或移出字節,這種搬運的過程便稱爲流(stream)。程序只需要關心是否正確地輸出了字節數據,以及是否正確地輸入了要讀取字節數據,特定I/O設備的細節對程序員是隱藏的。

文件處理方法

  • 緩衝文件系統:高級文件系統,系統自動爲正在使用的文件開闢內存緩衝區
  • 非緩衝文件系統:低級文件系統,由用戶在程序中爲每個文件設定緩衝區
    這裏寫圖片描述

文件句柄(實際上就是一個結構體變量)

typedef struct
{
    short level; //緩衝區“滿”或者“空”的程度
    unsigned flags; //文件狀態標識
    char fd; //文件描述符
    unsigned char hold; //如無緩衝區不讀取字符
    short bsize; //緩衝區的大小
    unsigned char *buffer; //數據緩衝區的位置
    unsigned ar; //指針,當前的指向
    unsigned istemp; //臨時文件,指示器
    short token; //用於有效性的檢查
}FILE;

文件操作API

fgetc  fputc   按照字符讀寫文件
fputs  fgets   按照行讀寫文件 (讀寫配置文件)
fread  fwirte   按照塊讀寫文件 (大數據塊遷移)
fprintf  fscanf  按照格式化進行讀寫文件

char ch;
    ch=fgetc(stdin);  //std -> 鍵盤
    fputc(ch, stdout); //stdout->屏幕
    fputc(ch,stderr); //stderr ->屏幕,錯誤信息

絕對路徑和相對路勁的區別

絕對路徑指的是:C:\Users\apple\Documents\C提高視頻\03.txt【針對windows平臺】
相對路徑指的是:/,45度, ./, ../(建議)【針對linux和windows平臺】
VS:編譯代碼時,相對於項目工程
直接運行可執行程序,相對於程序

int main()
{


    //用相對路徑來讀取文件時,一定要將文件與可執行程序放在一個文件夾中
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp,"./03.txt", "r+");
        if (fp == NULL)
        {
            perror("fopen");
            system("pause");
            return -1;
        }
        printf("\n");
    system("pause");
    return 0;
}

下面舉一個例子,以相對路徑創建一個文件,並用fputc函數將字符串寫入文件中:

void my_fputs(char *path)
{
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp, path, "w+");
    if (fp == NULL)
    {
        perror("my_fputs fopen");
        return;
    }
    //寫文件
    char buf[] = "this is a test for fputs";
    int n = strlen(buf);
    int i = 0;
    for (i = 0; i < n; i++)
    {
        //fputc的返回值是成功寫入文件的字符
        int ch = fputc(buf[i], fp);
        printf("ch = %c\n", ch);
    }
    if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }
}

int main()
{

    my_fputs("../03.txt");//文件的存放方式是以相對路徑存放的



    printf("\n");
    system("pause");
    return 0;
}

剛剛寫文件自己編了一個my_fputs函數來實現,現在要實現讀文件,再編一個my_fgets函數來實現,代碼如下:

void my_fgets(char *path)
{
    FILE *fp = NULL;
    errno_t err;
    err = fopen_s(&fp, path, "r+");
    if (fp == NULL)
    {
        perror("my_fgets fopen");
        return;
    }
    char ch;
    while(ch = fgetc(fp) != EOF)
    {
        printf("%c",ch);
    }
    printf("\n");
    if(fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }

}

最後在main函數中調用my_fgets(“../03.txt”);就可以實現在顯示屏上打印出“03.txt”文件中的字符串。
這裏寫圖片描述

按照塊讀寫文件

#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"


typedef struct
{
    char name[50];
    int id;
}Stu;


void my_fwrite(char *path)
{
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp, path, "w+");
    if (fp == NULL)
    {
        perror("my_fputs fopen");
        return;
    }

    Stu s[3];
    int i = 0;
    char buf[50];

    for (i = 0; i < 3; i++)
    {
        sprintf_s(buf, "stu%d%d%d", i, i, i);
        strcpy_s(s[i].name, buf);

        s[i].id = i + 1;

    }

    //寫文件
    //s,寫入文件內容的內存首地址
    //sizeof(Stu):塊數據的大小
    //3:寫數據的塊數。那麼寫文件數據的大小就是sizeof(Stu)*3
    //fp:文件指針
    //返回值ret爲成功寫入文件的塊數目

    int ret = fwrite(s, sizeof(Stu),3,fp);
    printf("ret = %d\n", ret);
    if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }

}


void my_fread(char *path)
{
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp, path, "r+");
    if (fp == NULL)
    {
        perror("my_fputs fopen");
        return;
    }

    Stu s[3];

    //讀文件
    //s,要讀的文件內容的內存首地址
    //sizeof(Stu):塊數據的大小
    //3:寫數據的塊數。那麼寫文件數據的大小就是sizeof(Stu)*3
    //fp:文件指針
    //返回值ret爲成功度取文件的塊數目

    int ret = fread(s, sizeof(Stu), 3, fp);
    printf("ret = %d\n", ret);
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        printf("%s,%d\n", s[i].name, s[i].id);
    }

    if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }

}


int main()
{

    my_fwrite("../05.txt");
    my_fread("../05.txt");

    printf("\n");
    system("pause");
    return 0;
}

讀寫結果如下:
這裏寫圖片描述

按照格式化讀寫文件

void my_fprintf(char *path)
{
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp, path, "w+");
    if (fp == NULL)
    {
        perror("my_fprintf fopen");
        return;
    }


    fprintf(stdout,"hello,today is %d",20171206);  //和printf("hello,today is %d",20171206);功能一樣
    fprintf(fp,"hello,today is %d",20171206);//寫入文件中了


    if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }
}

void my_fscanf(char *path)
{
    errno_t err;
    FILE *fp = NULL;
    err = fopen_s(&fp, path, "r+");
    if (fp == NULL)
    {
        perror("my_fscanf fopen");
        return;
    }
    int a =0;
    fscanf(fp,"hello,today is %d",&a);
    printf("a = %d",a);

if (fp != NULL)
    {
        fclose(fp);
        fp = NULL;
    }
}

隨機位置讀文件

int fseek(FILE *stream,long offset,int whence);
//返回值:成功返回0,出錯返回-1並設置errno; offset是偏移量;whence是參考點

long ftell(FILE *stream);
//返回值:成功返回當前讀寫位置,出錯返回-1並設置errno;測光標移動的長度

void rewind(FILE *stream); //將光標恢復到文件最開始的地方

fseek函數中的參數offset和whence共同決定了讀寫位置移動到何處,whence參數的含義如下:
SEEK_SET:
從文件開頭移動offset個字節
SEEK_CUR:
從當前位置移動offst個字節
SEEK_END:
從文件末尾向之前移動-offset個字節

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