C語言中炫酷的文件操作實例詳解
什麼是文件
磁盤上的文件是文件
但是在程序設計中,我們一般談的文件有兩種:程序文件和數據文件(從文件功能的角度來分類)。
程序文件
包括源程序文件(例如.c文件)目標文件(windows環境後綴為.obj)可執行程序(windos環境後綴為exe)。
數據文件 (本文重點)
文件的內容不一定是程序,而是程序運行時讀寫的數據,比如程序運行需要從中讀取數據的文件,或者輸出內容的文件。
文件名
文件就像人一樣,他也要有姓氏和名字來讓其他文件或者人知道這個文件是誰。
對於每一個文件要,,都有一個唯一的文件標識,以便用戶識別和引用。
文件名格式:文件路徑+文件名主幹+文件後綴
例如:D:\CSDN\Test.txt
為瞭方便起見,我們叫文件標識為文件名
文件的打開和關閉
文件指針
我們知道,指針是指向一個地址的,整形指針指向一個整形的空間,數組指針指向一個數組的空間,那麼文件指針自然就是指向文件的指針瞭。
每個被使用的文件都在內存中開辟瞭一個相應的文件信息區,用來存放文件的相關信息(如文件的名字,文件狀態及文件當前的位置等)。這些信息是保存在一個結構體變量中的。該結構體類型是有系統聲明的,取名FILE。
這是再vs的stdio頭文件下的文件信息區結構體
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE; //不同的C編譯器的FILE類型包含的內容不完全相同,但是大同小異。
就像學生要有學號姓名年齡這些信息一樣,文件也有他的信息,比如這個文件的地址。這些信息存放於這個結構體中,通過typedef重命名為FILE,並且我們不需要關心一些細節(你會關心我昨天晚上吃瞭什麼嗎)。
一般都是通過一個FILE的指針來維護這個FILE結構的變量,這樣使用起來更加方便。
下面我們可以創建一個FILE*的指針變量:
FILE* pf;
pf通過該文件信息區中的信息就能夠訪問該文件。
也就是說,通過文件指針變量能夠找到與它關聯的文件。
但上面的文件指針並未指向明確的位置,他暫時是一個野指針。
所以接下來,我們來學習如何打開(創建)一個文件。
文件函數
文件在讀寫之前應該先打開文件,在使用結束之後應該關閉文件。
在編寫程序的時候,在打開文件的同時,都會返回一個FILE*的指針變量指向該文件,也相當於建立瞭指針和文件的關系。
ANSIC規定使用fopen函數來打開文件,fclose來關閉文件。
//打開文件 FILE* fopen(const char *filename,const char *mode); //第一個參數是文件名,第二個參數是打開方式 //關閉文件 int Fclose(FILE *stream);
部分打開方式如下圖
現在我們來練習一下打開文件
//打開文件 FILE* pf = fopen("data.txt","r"); //以隻讀的方式打開這個文件 //如果文件打開失敗會返回空,否則會返回指向該文件的指針 if (pf == NULL){ perror("fopen"); return -1; } //讀文件 //關閉文件 fclose(pf); pf = NULL; return 0;
但是卻打開失敗瞭!!
原因是,從上面的打開方式一圖我們可以看出,以”r”方式打開,需要該文件真實存在,但是我並沒有創建這個文件,所以打開失敗瞭
叮~文件創建成功
我們再來看執行結果
這回沒有報錯
但是,這裡是將data.txt文件放在瞭該.c文件目錄下,在我將該文件放在別的地方,仍然打開失敗報錯。
原因是,我們這段代碼隻輸入瞭文件名,所以他隻在當前文件目錄下尋找該文件,在其他地方的文件我們就找不到瞭。
這裡我們來看看兩個東西,一個叫相對路徑,一個叫絕對路徑
相對路徑與絕對路徑
相對路徑
隻認為是當前目錄下的文件,如上面的代碼中。
絕對路徑
帶上文件的從磁盤到目標文件的路徑
例如
D:\Program Files\data.txt
但是請註意,在編程中,\是轉義字符,所以我們需要讓\不再是轉義字符,使其代表它本身
D:\Program Files\data.txt
輸入輸出流
什麼是輸入輸出流
學習過編程,一定知道printf或者cout或者System.out.println吧,
這些函數用於打印數據,這就是標準的輸出流。使數據輸出或者寫入文件中,我們叫輸出流。
我們打印HELLO WORLD在屏幕上,就是一個標準輸出流
像scanf之類的,從文件輸入或者讀數據到內存中,就是輸入流。
一些基本的輸入輸出函數如下。
比如,fputc就是寫一個字符進去,fgetc就是讀一個字符。
//打開文件 FILE* pf = fopen("data.txt","w"); if (pf == NULL){ perror("fopen"); return -1; } //讀文件 fputc('a', pf); fputc('b', pf); fputc('c', pf); //fputc第一個參數為輸入的字符,第二個使對應文件的指針 //關閉文件 fclose(pf); pf = NULL; return 0;
寫入瞭abc三個字符。
fputc和fgetc每次讀/寫一個字符後,文件指針pf會向後移動,類似strtok函數。會記錄上一次輸入/輸出的地址。
如果不這樣,那豈不是一直在一個位置重復寫入或者讀文件瞭。
接下來看看fgetc讀取字符
//打開文件 FILE* pf = fopen("data.txt","r"); if (pf == NULL){ perror("fopen"); return -1; } //讀文件 int a = fgetc(pf); printf("%c", a); a = fgetc(pf); printf("%c", a); a = fgetc(pf); printf("%c",a); //關閉文件 fclose(pf); pf = NULL; return 0;
執行結果
這就是順序讀寫,按著順序讀入寫入。
當然,有順序讀寫,就會有隨機讀寫
從字面意思就能看到,隨機讀寫emmm。
當然,除瞭fgetc這類,fgets自然就是讀取一行瞭(隻會讀/寫一行哦)
如果你用這類函數輸出在標準輸入或者標準輸入(stdout或者stdin)上,他和printf,scanf沒什麼區別。
接下來,我們來看二進制的讀和寫
二進制讀寫
fwirte
以二進制的形式將內容寫入文件中
第一個參數是你要寫入數據的數據地址,第二個參數是一個類型的大小(字節)。第三個參數是你要寫入幾個數據,第四個則是你選定寫入的流。
struct S{ int n; double d; char name[10]; }; int main() { struct S s = { 10, 3.14, "zhangsan" }; //打開文件 FILE* pf = fopen("data.txt","wb"); if (pf == NULL){ perror("fopen"); return -1; } //讀文件 fwrite(&s,sizeof(s),1,pf); //關閉文件 fclose(pf); pf = NULL; return 0; }
如上代碼會將數據以二進制的形式寫入data.txt
雖然我們看不懂,但是能看到zhangsan是我們輸入的內容
fread
以二進制的形式讀
和fwirte一樣,隻不過buffer不是const形式瞭,因為我們要將數據讀入該指針指向的目標。
struct S{ int n; double d; char name[10]; }; int main() { struct S s = {0}; //打開文件 FILE* pf = fopen("data.txt","rb"); if (pf == NULL){ perror("fopen"); return -1; } //讀文件 fread(&s,sizeof(struct S),1,pf); printf("%d %lf %s\n",s.n,s.d,s.name); //關閉文件 fclose(pf); pf = NULL; return 0; }
總結
到此這篇關於C語言中文件操作的文章就介紹到這瞭,更多相關C語言文件操作內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!