C語(yǔ)言常見(jiàn)的文件操作函數(shù)
一、文件的打開(kāi)和關(guān)閉
1、文件指針
每個(gè)被使用的文件都在內(nèi)存中開(kāi)辟了一個(gè)相應(yīng)的文件信息區(qū),用來(lái)存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類(lèi)型是有系統(tǒng)聲明的,取名FILE。
vs2013編譯環(huán)境提供的stdio.h頭文件中有以下文件類(lèi)型申明:
struct _iobuf { char *_ptr; int _cnt; char *_base; int _flag; int _file; int _charbuf; int _bufsiz; char *_tmpfname; }; typedef struct _iobuf FILE;
每當(dāng)打開(kāi)一個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,并填充其中的信息,一般都是通過(guò)一個(gè)FILE指針來(lái)維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,這樣使用起來(lái)更加方便。
下面我們可以創(chuàng)建一個(gè)FILE*的指針變量:
FILE* pf;//文件指針變量
通過(guò)文件指針變量能夠找到與它關(guān)聯(lián)的文件。
2、文件打開(kāi)和關(guān)閉
文件在讀寫(xiě)之前需要先打開(kāi)文件,使用結(jié)束后需要關(guān)閉文件。
規(guī)定使用fopen來(lái)打開(kāi)文件,fclose來(lái)關(guān)閉文件。
//打開(kāi)文件FILE* fp=fopen(const char* filename,const char* mode);//兩個(gè)參數(shù):打開(kāi)的文件名和打開(kāi)方式//關(guān)閉文件fcolse(fp);//打開(kāi)文件 FILE* fp=fopen(const char* filename,const char* mode); //兩個(gè)參數(shù):打開(kāi)的文件名和打開(kāi)方式 //關(guān)閉文件 fcolse(fp);
常見(jiàn)打開(kāi)文件方式如下:
文件打開(kāi)方式 | 含義 | 指定文件不存在 |
“r"(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)文本文件 | 出錯(cuò) |
"w"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本文件 | 建立一個(gè)新的文本文件 |
"a”(追加) | 向文件文本尾添加數(shù)據(jù) | 出錯(cuò) |
"rb"(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
"wb"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 建立一個(gè)新的二進(jìn)制文件 |
"ab"(追加) | 向二進(jìn)制文件尾添加數(shù)據(jù) | 出錯(cuò) |
打開(kāi)關(guān)閉文本文件示例如下:
該文件以只寫(xiě)方式打開(kāi),當(dāng)代碼路徑下不存在該文本文件時(shí),程序運(yùn)行會(huì)自動(dòng)生成新的文件;如果以只讀方式打開(kāi)文件,該文本文件不存在時(shí),程序運(yùn)行后會(huì)顯示打開(kāi)失敗。
#include<stdio.h> int main() { FILE* fp = fopen("text1.txt", "w");//打開(kāi)文件文本 if (fp == NULL)//判斷是否打開(kāi)成功 { printf("Open File Error\n"); return; } fclose(fp);//關(guān)閉文件文本 return 0; }
二、文件的順序讀寫(xiě)
功能 | 函數(shù)名 | 適用范圍 |
字符輸入函數(shù) | fgetc | 所有輸入流 |
字符輸出函數(shù) | fputc | 所有輸出流 |
文本行輸入函數(shù) | fgets | 所有輸入流 |
文本行輸出函數(shù) | fputs | 所有輸出流 |
格式化輸入函數(shù) | fscanf | 所有輸入流 |
格式化輸出函數(shù) | fprintf | 所有輸出流 |
二進(jìn)制輸入函數(shù) | fread | 文件 |
二進(jìn)制輸出函數(shù) | fwrite | 文件 |
1、fgetc()和fputc()函數(shù)
- fgetc()函數(shù)是從指定文件中讀取一個(gè)字符,讀取到文件末尾或者讀取失敗時(shí)返回EOF。
- fputc()函數(shù)用法如下:
int fputc(int ch,FLEF* fp);
ch為要寫(xiě)入的字符,fp為文件指針。
注:每寫(xiě)入一個(gè)字符,文件內(nèi)部位置指針向后移動(dòng)一個(gè)字節(jié)。
2、fgets()和fputs()函數(shù)
fgets()函數(shù)用法如下:
char* fgets(char* buf,int n,FILE* fp);
buf為存儲(chǔ)字符串的地址,n為讀取字符串的長(zhǎng)度,fp為文件的指針。該函數(shù)每次最多只能讀取一行,遇到\n就會(huì)停止讀取,若有多行需要循環(huán)讀取。
fputs()函數(shù)用法如下:
int fputs(const char* str,FILE* fp);
str為要寫(xiě)入文件的字符串,fp為要操作的文件,返回值為0表示成功。寫(xiě)入的字符串也是以\n結(jié)束,所以多行寫(xiě)入需要重復(fù)操作。
3、fscanf()和fprintf()函數(shù)
fscanf()和fprintf()函數(shù)與前面使用的scanf()和printf()函數(shù)功能相似,都是格式化讀寫(xiě)函數(shù),兩者的區(qū)別在于fscanf()和fprintf()函數(shù)讀寫(xiě)對(duì)象不是鍵盤(pán)和顯示器,而是磁盤(pán)文件。
兩個(gè)函數(shù)原型為:
int fscanf(FILE* fp,char* fromat,……); int fprintf(FILE* fp,char* format,……);
與scanf()和printf()相比,僅僅多了一個(gè)fp參數(shù)。
4、fread()和fwrite()函數(shù)
(1)fread()函數(shù)
用于讀取二進(jìn)制數(shù)據(jù)
size_t fread(void* buf,size_t size,size_t count,FILE* fp);
- fread返回實(shí)際讀取的完整項(xiàng)目數(shù),如果發(fā)生錯(cuò)誤或在達(dá)到計(jì)數(shù)之前遇到文件結(jié)尾,則該值可能小于計(jì)數(shù)。使用feof或ferror函數(shù)區(qū)分讀取錯(cuò)誤和文件結(jié)束情況。如果大小或計(jì)數(shù)為0,則fread返回0且緩沖區(qū)內(nèi)容不變。
- buf為內(nèi)存區(qū)塊的指針,用來(lái)存放讀取到的數(shù)據(jù)。
- size表示每個(gè)數(shù)據(jù)塊的字節(jié)數(shù)。
- count表示要讀取的數(shù)據(jù)塊的個(gè)數(shù)。
- fp文件指針。
(2)fwrite()函數(shù)
size_t fwrite(const void* buf,size_t size,size_t count,FILE* fp);
fwrite返回實(shí)際寫(xiě)入的完整項(xiàng)的數(shù)量,如果發(fā)生錯(cuò)誤,該數(shù)量可能小于count。buf用來(lái)存放要寫(xiě)入的數(shù)據(jù),其余參數(shù)與fread()寒素相同。
三、文件的隨機(jī)讀寫(xiě)
1、fseek函數(shù)
根據(jù)文件指針位置和偏移量來(lái)定位文件指針
int fseek(FILE* stream,long int offset,int origin);
第一個(gè)參數(shù)為文件指針;第二個(gè)參數(shù)為偏移量,正數(shù)表示向右偏移,負(fù)數(shù)表示向左偏移;第三個(gè)參數(shù)設(shè)定從文件的哪里開(kāi)始偏移,可能取值:SEEK_CUR、SEEK_END、SEEK_SET。
- SEEK_SET:文件開(kāi)頭
- SEEK_GUR:當(dāng)前位置
- SEEK_END:文件結(jié)尾
其中SEEK_SET、SEEK_CUR、SEEK_END依次為0、1、2。
2、ftell函數(shù)
計(jì)算文件指針相對(duì)于起始位置的偏移量
long int ftell(FILE* stream);
3、rewind函數(shù)
讓文件指針的位置回到文件的起始位置
void rewind(FILE* stream);
四、文本文件和二進(jìn)制文件
數(shù)據(jù)文件被分為文本文件和二進(jìn)制文件。
- 二進(jìn)制文件:數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ),不加轉(zhuǎn)換的輸出到外存。
- 文本文件:以ASCII字符的形式存儲(chǔ)的文件。如果要求在外存上以ASCII碼的形式存儲(chǔ),則需要在存儲(chǔ)前進(jìn)行轉(zhuǎn)換。
數(shù)據(jù)在內(nèi)存中的存儲(chǔ):字符以ASCII形式存儲(chǔ);數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲(chǔ),也可使用二進(jìn)制形式存儲(chǔ)。
例:正數(shù)10000,以ASCII碼的形式輸出到磁盤(pán),占用五個(gè)字節(jié)(每個(gè)字符一個(gè)字節(jié));而以二進(jìn)制形式輸出,在磁盤(pán)上只占用四個(gè)字節(jié)。
五、文件讀取結(jié)束的判定
- feof()函數(shù)用來(lái)判斷文件內(nèi)部指針是否指向文件末尾,當(dāng)指向文件末尾時(shí)返回非零值,否則返回零值。
- ferror()函數(shù)用來(lái)判斷文件操作是否出錯(cuò),出錯(cuò)時(shí)返回非零值,否則返回零值。
注:在文件讀取過(guò)程中,不能使用feof()函數(shù)的返回值來(lái)直接判斷文件是否結(jié)束。而是應(yīng)用于當(dāng)文件讀取結(jié)束時(shí),判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束。
1、文本文件讀取是否結(jié)束,判斷返回值是否為EOF(fgetc)、NULL(fgets)
例如:
- fgetc判斷是否為EOF
- fgets判斷返回值是否為NULL.
2、二進(jìn)制文件的讀取結(jié)束判斷,判斷返回值是否小于實(shí)際要讀的個(gè)數(shù)。
例如:
- fread判斷返回值是否小于實(shí)際要讀的個(gè)數(shù).
六、文件緩沖區(qū)
從內(nèi)存向磁盤(pán)輸出數(shù)據(jù)會(huì)先送到內(nèi)存中的緩沖區(qū),裝滿(mǎn)緩沖區(qū)后再一起送到磁盤(pán)上。如果從磁盤(pán)像計(jì)算機(jī)讀入數(shù)據(jù),則從磁盤(pán)文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿(mǎn)緩沖區(qū)),然后再?gòu)木彌_區(qū)逐個(gè)地將數(shù)據(jù)送到程序緩沖區(qū)。
#include <stdio.h> #include <windows.h> int main() { FILE*pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先將代碼放在輸出緩沖區(qū) printf("睡眠10秒-已經(jīng)寫(xiě)數(shù)據(jù)了,打開(kāi)test.txt文件,發(fā)現(xiàn)文件沒(méi)有內(nèi)容\n"); Sleep(10000); printf("刷新緩沖區(qū)\n"); fflush(pf);//刷新緩沖區(qū)時(shí),才將輸出緩沖區(qū)的數(shù)據(jù)寫(xiě)到文件(磁盤(pán)) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此時(shí),再次打開(kāi)test.txt文件,文件有內(nèi)容了\n"); Sleep(10000); fclose(pf); //注:fclose在關(guān)閉文件的時(shí)候,也會(huì)刷新緩沖區(qū) pf = NULL; return 0; }
因?yàn)橛芯彌_區(qū)的存在,C語(yǔ)言在操作文件的時(shí)候,需要用fflush函數(shù)刷新緩沖區(qū)或者在文件操作結(jié)束的時(shí)候關(guān)閉文件。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語(yǔ)言詳細(xì)分析常見(jiàn)字符串函數(shù)與模擬實(shí)現(xiàn)
字符串函數(shù)(String?processing?function)也叫字符串處理函數(shù),指的是編程語(yǔ)言中用來(lái)進(jìn)行字符串處理的函數(shù),如C,pascal,Visual以及LotusScript中進(jìn)行字符串拷貝,計(jì)算長(zhǎng)度,字符查找等的函數(shù)2022-03-03深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
本篇文章是對(duì)Main函數(shù)中的參數(shù)argc,argv的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C字符串操作函數(shù)的實(shí)現(xiàn)詳細(xì)解析
以下是對(duì)C語(yǔ)言中字符串操作函數(shù)的實(shí)現(xiàn)進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-08-08C++?實(shí)現(xiàn)單鏈表創(chuàng)建、插入和刪除
這篇文章主要介紹了C++?實(shí)現(xiàn)單鏈表創(chuàng)建、插入和刪除方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07c++實(shí)現(xiàn)簡(jiǎn)單隨機(jī)數(shù)的代碼
在本篇文章里小編給大家整理的是一篇關(guān)于c++實(shí)現(xiàn)簡(jiǎn)單隨機(jī)數(shù)的代碼內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。2021-05-05深入分析Visual C++進(jìn)行串口通信編程的詳解
本篇文章是對(duì)Visual C++進(jìn)行串口通信編程進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05