1. 程式人生 > >C++ 基礎 (12) 檔案的操作 FILE

C++ 基礎 (12) 檔案的操作 FILE

  1. 課程回顧

 

結構體基本操作:

 

  1. 結構體型別的定義

// struct為關鍵字 Stu為自定義識別符號
// struct Stu才是結構體型別

// 結構體成員不能在定義型別時賦值

struct Stu

{

        int age;

        char name[50];

    int score;

} // 後面有分號

 

2。結構體的定義和初始化

// 結構體變數初始化和陣列很類似,只有在定義時,才能初始化

// 定義結構體變數時,別忘了struct關鍵字

struct Stu obj = {18,”mike”,58}

 

3。結構體成員變數的使用

obj.age = 18;

(&obj)->age = 18;

 

2.結構體指標變數

1)       指標變數指向棧區

struct Stu *p = NULL;

struct Stu obj; //棧區結構體

p = &obj; //指向棧區

p ->age = 18;

(*p).age = 18;

   2) 指標變數指向堆區

          struct Stu *p = NULL;

 

          // 指向堆區

          p = (struct Stu *)malloc(sizeof(struct Stu));

          p -> age = 18;

 

          free(p);

         p = NULL;

 

3const修飾的指標變數

//看const修飾是*還是變數

const struct Stu *p (代表指標所指向的記憶體不能變

struct Stu const *p;(代表指標不能變

 

3.結構體陣列

stuct Stu obj[3] = {

  {18,”lily”,03},

  {18,”lily”,03},

  {18,”lily”,03},

}

 

struct Stu obj2[3] = {18,”lily”,99,22,”lucy”,-80,33….} // 這樣就比較不清晰了

 

struct Stu tmp[3]

int I = 0

 

for (I = 0;i<3;i++)

{

   (tmp +i)->age = 18+I;

(*(tmp+i)).age = 18+I; // .的優先順序高,所以要加括號

tmp[i].age = 18+I; //常用

}

 

4.結構體和函式

1)  同類型結構體變數賦值

struct Stu obj1 = {18,”lily”,99};

struct Stu obj2;

  • obj2 = obj1;

 

2)函式值傳遞

a)

struct Stu p;

// 結構體變數本身傳遞(值傳遞),形參修改不會影響到實參

// 呼叫完畢fun()函式,p的成員還是沒有賦值

fun(p)

void fun(struct stu p) //值傳遞,相當於拷貝了一份,所以並沒有變

{

  p.age = 18;

  strcpy(p.name,”mike”);

  p.score = 59;

}

 

 

 

 

3 函式地址傳遞

  struct Stu p;

  fun(&p);

  void fun(struct Stu *p)

  {

p->age = 18;

strcpy(p->name,”mike”);

p->score = 59;

}

 

 

5 結構體套一級指標

  struct stu

  {

int age;

char *name; // 一級指標

int score;

}; // 後面有分號

 

1)  棧區結構體

struct Stu s;

s.age =10;

s.name = (char *)malloc( strlen(“mike”) +1);

strcpy(s.name,”mike”);

s.score = 59;

 

free(s.name);

 

2堆區結構體

struct Stu *p; //結構體是指標,後面在堆區分配空間

p = (struct Stu *)malloc(sizeof(struct Stu))

p->name = (char *)malloc(strlen(“mike”)+1)

p->age = 18

strcpy(p->name,”mike”)

p->score = 59

 

free(p->name)

free(p)

 

 

列舉

 

typedef

 

#define INT int

 

巨集定義是在預處理階段,前面的替換後面的

 

typedef是在編譯階段,後面的替換前面的

 

2 作業講解

 

3 檔案概述

 

 

 

printf 把記憶體中的10先放到緩衝區,再放到螢幕

 

為什麼不直接列印到螢幕,而放到緩衝區呢?

為了效率,就是快取 (可能會拿很多次,

如果只拿一次,當然是直接給螢幕比較快,但是可能會拿很多次

 

 

 

FILE 所有平臺的名字都一樣,FILE是一個結構體型別,裡面的成員功能一樣,不同平臺成員的名字不一樣

FILE *fp

 

看一下stdio.h

為了相容改成typedef 最後轉成FILE

 

不同平臺成員不一樣

 

(vs2013 vs2015同一個平臺不同編譯器,裡面成員都不一樣

 

FILE所有平臺的名字都一樣,FILE是一個結構體型別,裡面的成員功能一樣,不同平臺成員的名字不一樣

 

FILE *fp

 

1、fp指標,只用呼叫了fopen(),在堆區分配空間,把地址返回給fp

2、fp指標不是指向檔案,fp指標和檔案關聯,fp內部成員儲存了檔案的狀態

 

char *p

 

*fp(不能這樣寫!!不是裡面是檔案,fp只是儲存了檔案的狀態

fd 檔案描述符

 

ulimit

 

1,2被佔用了 從3開始

 

 

 

 

3、操作fp指標 不能直接操作,必須通過檔案庫函式來操作fp指標

4、通過庫函式操作fp指標,對檔案的任何操作,fp內部成員會有相應的變化(作業系統自動完成)

 

結論:檔案的操作是需要作業系統層來支援的,通過檔案庫函式來操作,不是像普通指標一樣,p,*p這樣直接拿內容。

 

https://stackoverflow.com/questions/5130375/how-exactly-does-fopen-fclose-work

https://www.cnblogs.com/llguanli/p/6791507.html

 

4 檔案分類

 

 

分為裝置檔案和磁碟檔案

 

5 檔案操作流程

 

1、  開啟檔案fopen()

2、  讀寫檔案

a) 按字元讀寫fgetc(),fputc()

b) 按字串(行)讀取檔案fgets(),fputs()

c) 檔案結尾判斷 feof()          // end of file

3、  關閉檔案flose()

 

6 標準檔案裝置指標

 

 fp指向堆區一片空間,空間中的資料和硬碟種的關聯了

 

檔案指標

stdin,stdout,stderr

 

 

 

7 標準裝置補充

 

8 檔案的開啟關閉

 

FILE *fp = NULL;

 

//1、windows路徑寫法 因為\是轉義字元,所以需要\\

fl = fopen(“D:\\1.txt”,”w”); //windows

fp = fopen(“D:/1.txt”,”w”); //linux,windows

 

// 當前路徑

fp = fopen(“a.txt”,”w”)

fp = fopen(“./a.txt,”w”)

 

//絕對路徑

fp = fopen(“/home/edu/a.txt”,”w”);

 

fopen會在堆區分配空間,返回堆區地址給fp

 

 

 

9 檔案路徑說明

相對路徑:

1、在linux,相對路徑相對於可執行程式

2、VS

   a,編譯同時執行程式,相對路徑是相對於.vcxproj(專案檔案)所在的路徑

   b, 如果直接執行程式,相對路徑線相對於可執行程式

 

3、Qt

   a, 編譯同時執行程式,相對路徑,相對於debug所在的路徑

   b, 如果直接執行程式,相對路徑相對於可執行程式

 

fopen(“1.txt”,”w”);

 

char *p = “1.txt”; //指向文字常量區

fopen(p,”w”);

 

char p[] = “1.txt” //棧區/陣列

fopen(p,”w”); //陣列名字是首元素地址

 

char *mode = “w”;

fopen(“1.txt”,mode);

 

 

 

10 上午知識複習

1.檔案的型別

文字檔案和二進位制檔案

2.檔案的開啟關閉

1.檔案指標

  FILE *fp;

   stdin  //0 標準輸入

   stdout //1 標準輸出

   stderr //2 標準出錯

2.檔案的開啟

  fopen(‘路徑’,’許可權w/r/a’)

3.檔案的關閉

 

11 fputc的使用

1 開啟檔案fopen()

2 讀寫檔案

3 關閉檔案f close

 

 

 

12 fputc的使用補充

 

 

 

13 fgetc的使用

 

 

1、如果是文字檔案,可以通過-1(EOF) 判斷檔案是否結尾

   (!ASCII碼沒有-1

 

 

 

#include <stdio.h>

#include <string.h>

 

void write_file()

{

    //1、開啟檔案

    FILE *fp = fopen("4.txt", "w");

 

    if (fp == NULL)

    {

        perror("write_file fopen");

        return;

    }

 

    //2、寫檔案

    char *p = "abcdef";

    int i = 0;

    int n = strlen(p);

    for (i = 0; i < n; i++)

    {

        fputc(p[i], fp);

    }

 

    //3、關閉檔案

    fclose(fp);

}

 

void read_file()

{

    //1、開啟檔案 以讀的方式開啟

    FILE *fp = fopen("4.txt", "r");

 

    if (fp == NULL)

    {

        perror("write_file fopen");

        return;

    }

 

    //2、讀檔案,每次讀一個字元

    char ch;

    // while (ch != -1) //EOF 文字檔案結尾預設是-1

    while (ch != EOF) // 有這個巨集

    {

        ch = fgetc(fp);

        // printf("ch = %c\n", ch); //以char形式打出

        printf("ch = %d\n", ch);  //以數字形式打出

    }

 

    //3、關閉檔案

    fclose(fp);

}

 

int main(int argc, char const *argv[])

{

 

    write_file();

    read_file();

    return 0;

}

 

14 feof的存在意義

 

1、如果是文字檔案,可以通過-1(EOF)判斷檔案是否結尾

2、如果是二進位制檔案,不能以-1判斷檔案結尾

3、feof()判斷檔案是否結尾,任何檔案都能判斷

 

 

15 feof的使用

 

feof(fp) // 如果到檔案結尾,返回真

1、如果第一次沒有對檔案進行讀操作,直接呼叫此函式,永遠返回真

2、此函式必須,先讀,再呼叫feof() 才有意義

3、呼叫此函式,游標不會自動往後移動

4、必須讀取後,才能判斷是否結束,判斷的是讀取的字元

 

(這個東西是判斷游標以前的字元

 

16 feof的使用補充

 

17 cat命令的實現

將mycat放在cat所在路徑

放到目錄裡 然後用mycat命令就可以了,C語言的cat命令就是這樣實現的

 

18 課堂答疑

 

19 vi命令的實現

 

不能用scanf 因為不能有回車 空格

 

gets 不能有回車

 

所以只能用fgets (可以有空格,也可以有回車

 

 

 

// 讀一點寫一點

 

20 課堂答疑

 

 

注意 fgets會儲存’\n’

 

21 fputs的使用

 

 

22 fgets的使用

 

 

讀一下,發現後面全都是mike

 

因為讀到檔案結尾的時候會接觸本次讀取,所以buf內的內容並沒有變,還是最後一行的內容,

 

用一下memset:

 

(邊界值的問題,現在也順便講解了memset怎麼用的

 

迴圈讀取:

 

解決方法:

(放前面

 

23 作業