一.為什么使用文件
之前我們寫的程序的數據都是存儲到內存里面的,當程序結束時,內存回收,數據丟失,
再次運行程序時,就看不到上次程序的數據,如果要程序的數據一直保存得使用文件
二.文件
文件一般可以分為倆種:
1.程序文件
包括源程序文件(后綴為 .c)、目標文件(Windows環境下后綴為 .obj)、可執行程序(Windows環境下后綴為 .exe)
2.數據文件
文件的內容不一定是程序文件,而是程序運行時讀寫的文件,比如程序運行時需要從中讀取數據的文件或輸出的文件,舉例如下:
三.數據在文件中是怎么存儲的?
數據在內存是以二進制形式存儲,而在文件中:
字符一律按ASCLL碼值形式存儲
數值型數據既可以以ASCLL碼值形式存儲,也可以以二進制形式存儲
舉例:
如10000,以ASCLL碼值形式存儲到磁盤,在磁盤上占5個字節(一個字符一個字節),以二進制形式存儲,占4個字節,圖像如下:
四.二進制文件和文本文件
數據在內存是以二進制形式存儲,如果不加以轉化就輸出到外存的文件,就是二進制文件,
以ASCLL碼值形式存儲的文件為文本文件
五.流和標準流
1.流
程序的數據要輸出到各種設備,也需要從外部設備獲取數據,由于設備的不同導致輸入輸出操作不同,為了方便就有了流的概念,c程序對文件、鍵盤等進行輸入輸出操作都是通過流操作的
一般情況下,向流中輸入輸出數據都是先打開流,在進行操作
2.標準流
之前的scanf函數從鍵盤輸入信息、primtf函數向屏幕輸出信息等卻沒看見打開流,是因為c程序在啟動的時候默認打開了三個流:
stdin ---標準輸入流,大多數環境下從鍵盤上輸入,scanf就是從標準輸入流中讀取數據的
stdout ---標準輸出流,大多數環境下從屏幕上輸出,printf就是將信息輸出到標準輸出流中
stderr ---標準錯誤流,大多數環境下從屏幕上輸出
六.文件指針
每打開一個文件,系統就會根據文件情況自動創建FILE結構體變量,并填充其中的信息,一般都是通過一個FILE的指針來維護其結構變量,即文件指針,該指針可以找到與它關聯的文件
七.文件的打開和關閉
文件在讀寫前應該打開文件,使用結束后關閉文件,不然會造成內存泄漏,數據丟失等
ANSIC規定使用fopen打開文件,fclose關閉文件
1.fopen
形式:
功能:
打開fileaname指定的文件,同時將文件和一個流進行關聯,后續對流的操作是通過函數返回的指針進行維護的(如fputc、fputs等),具體對流(關聯的文件)的操作是通過參數mode來指定的
參數:
filename:表示打開文件的名字,可以是相對路徑,也可以是絕對路徑
mode:表示打開文件的操作方式
返回值:
打開文件成功返回一個指向FILE結構體的指針,通過操作流(統一接口)指向文件信息區,關聯到此文件
失敗時返回NULL,所以每次打開文件都要檢查是否打開成功
文件打開方式(mode參數)
模式 | 描述 | 文件存在 | 文件不存在 |
“? r? ” | 只讀 | 正常打開文件 | 返回NULLL |
“ w ” | 只寫(覆蓋) | 清空文件類容 | 創建新文件 |
" a " | 追加寫入(從末尾) | 從末尾寫入 | 創建新文件 |
" r+ " | 讀寫(從開頭) | 正常打開文件 | 返回NULL |
" w+ " | 讀寫(覆蓋) | 清空文件類容 | 創建新文件 |
" a+ " | 讀寫(追加) | 從末尾寫入 | 創建新文件 |
"rb""wb"等 | 二進制模式(加b) | 同上 | 同上 |
2.fclose
形式:
功能:
關閉參數steam關聯的文件,并取消其關聯關系。與該流關聯的內部緩沖區解除關聯并刷新(將為寫入磁盤的輸入緩沖區的類容寫入,將未讀取的輸出緩沖區的類容丟棄)所以文件指針會變為野指針,得及時置為NULL
參數:
steam:指向要關閉文件流的FILE結構體的指針
返回值:
關閉成功返回0,否則返回EOF
應用舉例:
.? ----表示當前路徑
..? ----表示上一級路徑
/ ----表示分割目錄層級
相對文件舉例:data.txt(表示當前路徑的data.txt)或(./../data.txt)
絕對路徑舉例:C:\Users\xxx\Desktop
八.文件的順序讀寫
函數名 | 功能 | 適用于 |
fgetc | 從輸入流讀取一個字符 | 所有輸入流 |
fputc | 向輸出流寫入一個字符 | 所有輸出流 |
fgets | 從輸入流讀取一個字符串 | 所有輸入流 |
fputs | 向輸出流寫入一個字符串 | 所有輸出流 |
fscanf | 從輸入流讀取帶有格式的數據 | 所有輸入流 |
fprintf | 向輸出流寫入帶有格式的數據 | 所有輸出流 |
fread | 從輸入流讀取一塊數據 | 文件輸入流 |
fwrite | 向輸出流寫入一塊數據 | 文件輸出流 |
1.fputc
形式:
功能:
將參數character指定的字符寫入到stream指定的輸出流里,字符會被寫入內部指示器當前指向的位置(如有字符將被覆蓋),寫入后指示器向前移動一個位置
參數:
character:被寫入的字符
steam:指針,指向了輸出流
返回值:
寫入成功返回寫入的字符(int形式的)
失敗時返回EOF(通常為-1)
應用:
2.fgetc
形式:
功能:
從參數stream指定的輸入流讀取字符,讀取當前指示器指向的字符后,指示器也會向前移動一個位置
參數:指針,指向了輸入流
返回值:
讀取成功時返回讀取的字符(int類型的)
讀取失敗或讀取到文件末尾時返回EOF
應用:
2.feof和ferror
feof
形式:
功能:
檢測stream指針指向的流是否遇到了文件末尾。如果在讀取文件到末尾的時候,讀取就會停止,這時讀取函數就會在對應的流上設置一個文件結束的指示符,這個指示符會被 feof() 檢測到,如果檢測到指示符就返回非0的值,否則返回0
ferror
形式:
功能:
檢測stream指針指向的流是否讀/寫錯誤。如果讀/寫錯誤,文件讀寫就會停止,讀寫函數就會在對應的流上設置一個錯誤指示符,這個指示符會被ferror檢測到,被檢測到指示符被設置就會返回非0的值,否則返回0.
應用:
3.fputs
形式:
功能:
將str指向的字符串寫入到stream指向的輸出流里(不包括文件的控制符\0)
參數:
str:指針,指向要寫入的字符串(必須以\0結尾)
stream:指針,指向輸出流
返回值:
成功時返回非負數
失敗時返回EOF
應用:
4.fgets
形式:
功能:
從stream指定的輸入流讀取字符串,直至讀到換行符、文件末尾、指定字符數(包括結尾\0),然后將讀取的字符串存儲到str指向的空間里
參數:
str:指向字符數組的指針,用來存儲讀取的字符
num:最大讀取字符數(實際最多讀取num-1個,每次讀取都會在結尾加\0)
stream:指針,指向輸入流
返回值:
成功時返回str
讀取到文件末尾或讀取錯誤時返回NULL
應用:
5.fprinrf
形式:
功能:
將格式化數據輸出到stream指定的流里
參數:
stream:指針,指向要寫入的文件流里
format:格式化字符串(%d、%f等)
....? :提供與格式化字符串中說明符
返回值:
成功時返回寫入字符個數
失敗時返回負值
應用:

6.fscanf
形式:
功能:
從stream指定的文件流中讀取格式化數據的函數
參數:
stream:指針,指向輸入流
.... :可變參數列表,提供存儲數據的地址
其他和scanf一樣
返回值:
成功時返回成功填充到可變參數列表的項數,但可能少于預期,有如下原因:
格式化字符與數據不匹配
讀取發生錯誤
在讀取成功前讀到文件末尾或讀取錯誤返回EOF
應用:
7.fwrite
形式:
功能:
將ptr指向的數據塊(可控制)寫入到stream指向的輸出流里(以二進制寫入,所以得在使用前已二進制可寫方式打開)
參數:
ptr:指針,指向要寫入的數據塊
size:要寫入每個數據塊的大小(單位字節)
num:要寫入數據項的數量
stream:指針,指向了要寫入的文件輸出流
返回值:
返回寫入的項數
應用:
8.fread
形式:
功能:
從stream指定的文件輸入流中讀取數據塊(讀取二進制形式文件)
參數:
ptr:指針,指向存儲讀取的數據的空間
size:要讀取每個數據塊的大小
count:讀取數據塊的總量
stream:指針,指向要讀取數據的文件流
返回值:
讀取的項數
應用:

9.sprintf
形式:
功能:
將格式化數據轉化為一個字符串
參數:
str:指針,指向存儲生成的字符串
返回值:
成功時返回存儲的字符數(不包括\0)
失敗時返回負值
應用:
10.sscanf
形式:
功能:
從字符串讀取格式化數據
參數:
s:指針,指向要讀取的字符串
返回值:
成功時返回解析成功并賦值的項數
失敗時返回EOF
應用:
九.文件的隨機讀取
1.fseek
形式:
功能:
調整文件指示器的位置,可以從想讀/寫的位置讀/寫
參數:
stream:指針,指向一個流(如文件流)
origin:文件指示器的初始位置,可設置,有以下可能取值:
‘
offset:相對于origin的偏移量
應用:
2.ftell
形式:
功能:
返回文件指示器相對于起始位置的偏移量
應用:
3.rewind
形式:
功能:
是文件指針回到起始位置
十.文件緩沖區
系統會自動在內存中為程序中每一個正在使用的文件開辟一塊“文件緩沖區”。從內存向磁盤輸出數據先會送到文件緩沖區,裝滿后才一起送到磁盤上.
所以在讀寫模式下,寫完后再讀,可能數據還沒輸出到文件,導致讀不到數據,以下有個函數可以刷新文件緩沖區,能及時讀到數據,
fflush
形式:
功能:
強制刷新stream指定流的緩沖區,但對輸入流未定義
參數為NULL時刷新所有打開的輸出流
返回值:
成功時返回0,失敗時返回EOF
證明代碼:
#include <stdio.h>
#include <windows.h>
//VS2022 WIN11環境測試
int main()
{FILE* pf = fopen("dtat.txt", "w");fputs("abcdef", pf);//先將代碼放在輸出緩沖區printf("睡眠10秒-已經寫數據了,打開dtat.txt文件,發現文件沒有內容\n");Sleep(10000);printf("刷新緩沖區\n");fflush(pf);//刷新緩沖區時,才將輸出緩沖區的數據寫到?件(磁盤)//注:fflush 在?版本的VS上不能使?了printf("再睡眠10秒-此時,再次打開dtat.txt文件,文件有內容了\n");Sleep(10000);fclose(pf);//注:fclose在關閉?件的時候,也會刷新緩沖區pf = NULL;return 0;
}