前些時候,我們學習的C語言程序都是由輸入輸出和算法組成的控制臺程序。我們在終端上來輸入我們提供的數據,然後程序也會通過終端來告訴我們最終運行的結果。
但是,可能有的同學已經觀察到了,我們日常使用的別人開發的程序,大多數都是通過文件來提供數據的。比如一個Excel的報表,程序可以直接來分析裡面的數據。再比如,一個TXT格式的電子書,程序可以直接分析有多少字、多少個章節,甚至還可以生成出一個目錄來。
擁有這樣能力的程序,是不是感覺功能強大了許多?這就要用到我們今天要講到的內容——「文件操作」。
在我們比較熟悉的Windows系統下,文件類型的區分是用「擴展名」來進行的。但其實擴展名並不是指「文件格式」,它只是一個「門牌號」而已。至於它到底對不對,那系統就不知道了。可能有很多的新手,在遇到格式的問題的時候,會認為直接更改擴展名,就能實現格式轉換。不瞞你們說,我小時候也有過這種想法。但是後來發現,不行。舉個例子,現在有一個 MP3 的文件,要轉成 AAC。這兩個文件從編碼上來講,就是不一樣的。MP3 只能用 MP3 的方式去讀取,AAC 只能用 AAC 的方式去讀取。如果你把擴展名直接改成 AAC,那麼系統就被你騙了,就會用 AAC 的方式去讀取實際還是 MP3 的文件,當然是不行了。
不同的擴展名,就對應了不同的讀取方式。「EXE」 就代表 Windows 系統下的可執行二進位文件,「TXT」是純文本文件,等等。
在 Linux 和 Unix 作業系統下,文件的定義就寬泛多了。不光軟體,硬體也可以叫文件。也就是說,硬體實際上也是當做文件的方式來處理的。
在C語言中,文件一般分為兩種,一種是二進位文件,就是我們編譯出來的那個東西,我們是看不懂的;另一種是文本文件,也就是我們常說的原始碼。
我們要對一個文件進行操作,首先我們需要把文件打開,然後才能讀或者寫。對文件操作完成後,我們還要將文件關閉。
C語言中的打開文件使用fopen函數,通式如下:
fopen(&34;, &34;)
如果打開文件成功,則會返回一個FILE結構的指針,通過這個指針,我們就可以對這個文件進行操作;如果打開文件失敗,則會返回NULL。
下面是所有的模式:
前面幾個都好理解,只是最後一個,為啥要區分一個二進位出來呢?
不加「b」的情況下,就是以文本的形式來打開。因為在不同的作業系統中,換行符是不同的。Unix系統用\n,MacOS用\r,而Windows用的是\r\n,那麼在文本模式下打開,C語言會根據系統環境的不同,來轉化換行符。而在二進位的模式下,就不會進行任何的轉換。
當你對文件操作完畢後,一定要記得把文件用fclose()函數來關閉。其實我們在打開文件後的所有操作,實際上都被記錄到了緩存裡,只有執行了關閉後,我們的更改才會生效。如果關閉成功,則函數會返回0;失敗的話,就會返回EOF。關閉成功後,我們創建的文件指針就會失效。
//Example 01//學習交流群:782648055include <stdlib.h>int main(void){ FILE* f; int chr; if ((f = fopen(&34;, &34;)) == NULL) { printf(&34;); exit(EXIT_FAILURE); } while ((chr = getc(f)) != EOF) { putchar(chr); } fclose(f); return 0;}
//file1.txt中的內容C programming makes me happy!
//Consequence 01C programming makes me happy!
打開了文件之後,就可以進行我們的操作了。
讀取單個字符,我們可以用fgetc和getc這兩個來實現。它們的作用,就是讀取一個字符,然後將光標移動到下一個位置。
include <stdio.h>...int fputc(int c, FILE* stream);int putc(int c, FILE* stream);
第一個參數是你要寫入的字符,第二個是你要寫入的文件流。
這裡就要用到fgets和fputs兩個函數了。
39;\0&include <stdio.h>include <time.h>int main(void){ FILE* fp; struct tm* p; time_t t; time(&t); p = localtime(&t); //寫入日期到文件 if ((fp = fopen(&34;, &34;)) == NULL) { printf(&34;); exit(EXIT_FAILURE); } fprintf(fp, &34;, 1900 + p -> tm_year, 1 + p -> tm_mon, p -> tm_mday); fclose(fp); //讀取文件日期,輸出到終端 int year, month, day; if ((fp = fopen(&34;, &34;)) == NULL) { printf(&34;); exit(EXIT_FAILURE); } fscanf(fp, &34;, &year, &month, &day); printf(&34;, year, month, day); fclose(fp); return 0;}
//date.txt中的內容2020-6-15
//Consequence 022020-6-15
我們用fopen函數可以用二進位的方式來打開一個文件,但實際上我們要用二進位的方式來讀寫,還得用相應的函數才行。
C語言提供了fread和fwrite兩個函數來實現二進位的讀取和寫入。
include <stdio.h>...long ftell(FILE* stream);
如果將一個文件看成一個數組,那麼這個函數返回的就是這個數組的下標。
//Example 01include <stdlib.h>int main(void){ FILE* fp; if ((fp = fopen(&34;, &34;)) == NULL) { printf(&34;); exit(EXIT_FAILURE); } printf(&34;, ftell(fp)); fputc(&39;, fp); printf(&34;, ftell(fp)); fputs(&34;, fp); printf(&34;, ftell(fp)); fclose(fp); return 0;}
//data.txt中的內容TechZone
//Consequence 010110
如果你想將光標快速移動到文件頭,可以用rewind函數來實現。
...rewind(fp);fputs(&34;, fp);fclose(fp);...
//data.txt中的內容Helloone
可以看到,它會覆蓋我們前面的數據。
有的同學可能會說了,你這不還是沒解決問題嗎?
好的,那就來解決下問題吧。C語言給我們提供了一個函數fseek,這個函數可以直接把光標跳轉到我們想要的位置。
34;打開文件失敗!\n&34;出錯了!\n&include <errno.h>...printf(&34;, errno);...
舉個例子:
打開文件失敗:2
但是這個錯誤代碼不是所有人都知道它的含義。所以C語言又提供了一個函數perror,它可以直接用文字來提示我們錯誤的地方。
34;打開文件失敗,原因是");...
結果是這樣的:
打開文件失敗,原因是:No such file or directory
中間的冒號是自動加上的。
或許以後在你的開發生涯中,用的最多的不是C語言,但這門語言對你帶來的提升,那是不可忽視的。最後,祝各位學有所成!
獲取完整視頻教程,可以關注B站:https://www.bilibili.com/video/BV1QE411y7v4