一文詳解C語言中文件相關(guān)函數(shù)的使用
一、文件和流
1、程序文件
包括源程序文件(后綴為.c)
目標(biāo)文件(windows環(huán)境后綴為.obj)
可執(zhí)行程序(windows環(huán)境 后綴為.exe)
2、數(shù)據(jù)文件
文件的內(nèi)容不一定是程序,而是程序運(yùn)行時(shí)讀寫的數(shù)據(jù),比如程序運(yùn)行需要從中讀取數(shù)據(jù)的文件, 或者輸出內(nèi)容的文件。
3、流
任何一個(gè)C程序,運(yùn)行起來就會(huì)默認(rèn)打開3個(gè)流
1、FILE* stdin(標(biāo)準(zhǔn)輸入流,鍵盤)
2、FILE* stdout(標(biāo)準(zhǔn)輸出流,顯示器)
3、FILE* stderr(標(biāo)準(zhǔn)錯(cuò)誤流,顯示器)
流可以理解為輸入/輸出緩沖區(qū)
二、文件組成
每個(gè)被使用的文件都在內(nèi)存中開辟了一個(gè)相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如文件的名 字,文件狀態(tài)及文件當(dāng)前的位置等)。這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是由系統(tǒng)聲明的,取名FILE
FILE*就是文件指針類型,可以通過文件指針找到它指向的文件信息區(qū)(FILE類型的結(jié)構(gòu)體),文件信息區(qū)用于維護(hù)一個(gè)文件(每個(gè)文件都是獨(dú)立的文件信息區(qū))
三、文件的打開和關(guān)閉
1、文件的打開fopen
filename是文件名
mode是文件打開方式
文件打開方式 | 含義 | 如果指定文件不存在 |
“r”(只讀) | 為了輸入數(shù)據(jù),打開一個(gè)已經(jīng)存在的文本文件 | 出錯(cuò) |
“w”(只寫) | 為了輸出數(shù)據(jù),打開一個(gè)文本文件 | 建立一個(gè)新的文件 |
“a”(追加) | 向文本文件尾添加數(shù)據(jù) | 建立一個(gè)新的文件 |
“rb”(只讀) | 為了輸入數(shù)據(jù),打開一個(gè)二進(jìn)制文件 | 出錯(cuò) |
“wb”(只寫) | 為了輸出數(shù)據(jù),打開一個(gè)二進(jìn)制文件 | 建立一個(gè)新的文件 |
“ab”(追加) | 向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù) | 出錯(cuò) |
“r+”(讀寫) | 為了讀和寫,打開一個(gè)文本文件 | 出錯(cuò) |
“w+”(讀寫) | 為了讀和寫,新建一個(gè)文本文件 | 建立一個(gè)新的文件 |
“a+”(讀寫) | 打開一個(gè)文件,在文件尾進(jìn)行讀寫 | 建立一個(gè)新的文件 |
“rb+”(讀寫) | 為了讀和寫打開一個(gè)二進(jìn)制文件 | 出錯(cuò) |
“wb+”(讀寫) | 為了讀和寫,新建一個(gè)新的二進(jìn)制文件 | 建立一個(gè)新的文件 |
“ab+”(讀寫) | 打開一個(gè)二進(jìn)制文件,在文件尾進(jìn)行讀和寫 | 建立一個(gè)新的文件 |
2、文件關(guān)閉fclose
stream是文件指針,文件使用完后一定要fclose關(guān)閉,并把文件指針置空。(用起來像free)
int main() { FILE* pf = fopen("text.txt", "r");//文件路徑可以是相對路徑或絕對路徑 if (pf == NULL) { printf("%s\n", strerror(errno)); exit(-1); } fclose(pf);//不關(guān)閉文件可能會(huì)造成數(shù)據(jù)丟失 pf = NULL; return 0; }
四、文件的順序讀寫
字符輸入函數(shù) | fgetc | 所有輸入流 |
字符輸出函數(shù) | fputc | 所有輸出流 |
文本行輸入函數(shù) | fgets | 所有輸入流 |
文本行輸出函數(shù) | fputs | 所有輸出流 |
格式化輸入函數(shù) | fscanf | 所有輸入流 |
格式化輸出函數(shù) | fprintf | 所有輸出流 |
二進(jìn)制輸入 | fread | 文件 |
二進(jìn)制輸出 | fread | 文件 |
1、使用fputc和fgetc寫入/讀取單個(gè)字符
寫入單個(gè)字符到文件
character:要寫入的字符
stream:指向輸出流 FILE 對象的指針。
int main() { FILE* pf = fopen("text.txt", "w");//文件路徑可以是相對路徑或絕對路徑 if (pf == NULL) { printf("%s\n", strerror(errno)); //perror("fopen");//void perror ( const char * str )用來將上一個(gè)函數(shù)發(fā)生錯(cuò)誤的原因輸出到標(biāo)準(zhǔn)設(shè)備(stderr) exit(-1); } for (char i = 'a'; i <= 'z'; i++) { fputc(i, pf);//輸出 } fclose(pf); pf = NULL; }
讀取文件中的單個(gè)字符
stream:指向輸入流 FILE 對象的指針。
int main() { pf = fopen("text.txt", "r");//文件路徑可以是相對路徑或絕對路徑 if (pf == NULL) { printf("%s\n", strerror(errno)); exit(-1); } printf("%c\n", fgetc(pf));//輸入,也可以寫一個(gè)循環(huán)讀取 printf("%c\n", fgetc(pf)); printf("%c\n", fgetc(pf)); printf("%c\n", fgetc(pf)); printf("%c\n", fgetc(pf)); fclose(pf); pf = NULL; return 0; }
2、使用fputs和fgets寫入/讀取一串字符
寫入一串字符到文件
str:要寫入的字符串的地址
stream:指向輸出流 FILE 對象的指針。
int main() { FILE* pf = fopen("text.txt", "w"); if (pf == NULL) { perror("fopen:"); exit(-1); } char arr[] = "abcde";//text.txt文件被寫入abcde fputs(arr, pf); fclose(pf); pf = NULL; return 0; }
讀取文件中num個(gè)字符
str:讀到的字符串放到str指向的空間里去
num:讀取的字符串個(gè)數(shù)
stream:指向輸入流 FILE 對象的指針。
讀取成功:返回str的地址
讀取失敗或錯(cuò)誤:返回空指針
監(jiān)視發(fā)現(xiàn),我們從文件中讀取5個(gè)字符,實(shí)際只讀了4個(gè),最后一個(gè)補(bǔ)了\0
3、使用fprintf和fscanf按照指定的格式寫入/讀取
stream:指向輸出流 FILE 對象的指針。
后續(xù)參數(shù)使用方法與printf一樣
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { "zhangsan",1510,66.5f }; FILE* pf = fopen("text.txt", "w"); if (pf == NULL) { perror("fopen:"); exit(-1); } fprintf(pf, "%s %d %f", s.name, s.tele, s.scores);//打印到txt文件 fprintf(stdout, "%s %d %f", s.name, s.tele, s.scores);//打印到屏幕 fclose(pf); pf = NULL; return 0; }
stream:指向輸入流 FILE 對象的指針。
后續(xù)參數(shù)使用方法和scanf一樣
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { 0 }; FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror("fopen:"); exit(-1); } fscanf(pf, "%s %d %f", s.name, &s.tele, &s.scores);//將文件中的內(nèi)容讀取到結(jié)構(gòu)體中 printf("%s %d %f", s.name, s.tele, s.scores); fclose(pf); pf = NULL; return 0; }
4、使用fwrite和fread按照二進(jìn)制的方式寫入/讀取
ptr:從ptr指向的當(dāng)前位置開始寫入
size:每個(gè)元素的大小
count:要寫入的元素個(gè)數(shù)
stream:指向輸出流 FILE 對象的指針。
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { "zhangsan",1510,66.5f }; FILE* pf = fopen("text.txt", "wb"); if (pf == NULL) { perror("fopen:"); exit(-1); } fwrite(&s, sizeof(struct S), 1, pf); fclose(pf); pf = NULL; return 0; }
fread參數(shù)和fwrite一樣
ptr:從ptr指向的當(dāng)前位置開始讀取
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { 0 }; FILE* pf = fopen("text.txt", "rb"); if (pf == NULL) { perror("fopen:"); exit(-1); } fread(&s, sizeof(struct S), 1, pf); printf("%s %d %f", s.name, s.tele, s.scores); fclose(pf); pf = NULL; return 0; }
5、使用sprintf和sscanf將格式化數(shù)據(jù)和字符串互相轉(zhuǎn)換(文件無關(guān))
將格式化數(shù)據(jù)轉(zhuǎn)換為字符串
str:將格式化數(shù)據(jù)放到目標(biāo)地址
后續(xù)參數(shù)和使用方式和printf一樣
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { "zhangsan",1510,66.5f }; char arr[60]={0}; sprintf(arr, "%s %d %f", s.name, s.tele, s.scores); printf("%s", arr); return 0; }
將字符串轉(zhuǎn)換為格式化數(shù)據(jù)
s:指向字符串的指針
后續(xù)參數(shù)和使用方式和scanf一樣
struct S { char name[20]; int tele; float scores; }; int main() { struct S s = { 0 }; char arr[60]={ "zhangsan 1510 66.5f" }; sscanf(arr, "%s %d %f", s.name, &s.tele,&s.scores); printf("%s %d %f", s.name,s.tele,s.scores ); return 0; }
五、文件的隨機(jī)讀寫
1、fseek(指定文件指針的位置)
注意:每次文件讀取完畢后,文件指針++
stream:指向標(biāo)識流的 FILE 對象的指針
offset:指針偏移量
origin:指針起始點(diǎn),如下圖:
SEEK_SET | 文件開頭 |
SEEK_CUR | 文件指針的當(dāng)前所處的位置 |
SEEK_END | 文件結(jié)尾 |
int main() { FILE* pf = fopen("text.txt", "r+"); if (pf == NULL) { perror("fopen:"); exit(-1); } fputs("abcde", pf); fseek(pf, 2, SEEK_SET); int ch = fgetc(pf);//該語句執(zhí)行完畢后,指針++,指向d printf("%c ", ch);//打印c fseek(pf, 0, SEEK_CUR); ch = fgetc(pf); //該語句執(zhí)行完畢后,指針++,指向e printf("%c ", ch);//打印d fseek(pf, -1, SEEK_END);//這里SEEK_END是指向e的后一個(gè) ch = fgetc(pf);//該語句執(zhí)行完畢后,指針++,指向e的后一個(gè) printf("%c ", ch);//打印e fclose(pf); pf = NULL; return 0; }
2、ftell(求文件指針與起始位置的偏移量)
int main() { FILE* pf = fopen("text.txt", "r+"); if (pf == NULL) { perror("fopen:"); exit(-1); } fputs("abcde", pf); fseek(pf, -1, SEEK_END);//這里SEEK_END是指向e的后一個(gè) int ch = fgetc(pf);//該語句執(zhí)行完畢后,指針++,指向e的后一個(gè) printf("%c ", ch);//打印e printf("%d", ftell(pf));//打印5,當(dāng)前指針在e的后一個(gè),相對于a相差5 fclose(pf); pf = NULL; return 0; }
3、rewind(讓文件指針回到起始位置)
六、文本文件和二進(jìn)制文件的區(qū)別
數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ),如果不加轉(zhuǎn)換的輸出到外存,就是二進(jìn)制文件。
如果要求在外存上以ASCII碼的形式存儲(chǔ),則需要在存儲(chǔ)前轉(zhuǎn)換。以ASCII字符的形式存儲(chǔ)的文件就是文本文件。 字符一律以ASCII形式存儲(chǔ),數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲(chǔ),也可以使用二進(jìn)制形式存儲(chǔ)。
七、文件讀取結(jié)束的標(biāo)志
文本文件讀取是否結(jié)束,fgetc判斷返回值是否為 EOF . fgets判斷返回值是否為 NULL
二進(jìn)制文件的讀取結(jié)束判斷,判斷返回值是否小于實(shí)際要讀的個(gè)數(shù)。 例如: fread判斷返回值是否小于還是等于實(shí)際要讀的個(gè)數(shù)。
feof:判斷文件是否讀到末尾而結(jié)束,返回值為真,就是讀到了文件結(jié)束
ferror:判斷文件是否讀取錯(cuò)誤而結(jié)束,返回值為真,就是文件讀取遇到了錯(cuò)誤
八、文件緩沖區(qū)
ANSIC 標(biāo)準(zhǔn)采用“緩沖文件系統(tǒng)”處理的數(shù)據(jù)文件的,所謂緩沖文件系統(tǒng)是指系統(tǒng)自動(dòng)地在內(nèi)存中為程序中每一個(gè)正在使用的文件開辟一塊“文件緩沖區(qū)”。
從內(nèi)存向磁盤輸出數(shù)據(jù)會(huì)先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤上。
如果從磁盤向計(jì)算機(jī)讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)。緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定的。
到此這篇關(guān)于一文詳解C語言中文件相關(guān)函數(shù)的使用的文章就介紹到這了,更多相關(guān)C語言文件相關(guān)函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何實(shí)現(xiàn)循環(huán)隊(duì)列
本文主要介紹了C語言循環(huán)隊(duì)列的實(shí)現(xiàn),對于數(shù)據(jù)結(jié)構(gòu)與算法的研究有所幫助,需要的朋友可以參考下2015-07-07Qt使用SQLite數(shù)據(jù)庫存儲(chǔ)管理圖片文件
這篇文章主要為大家詳細(xì)介紹了Qt如何使用SQLite數(shù)據(jù)庫實(shí)現(xiàn)存儲(chǔ)管理圖片文件的功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2023-04-04C++二叉樹的前序中序后序非遞歸實(shí)現(xiàn)方法詳細(xì)講解
前序遍歷的順序是根、左、右。任何一顆樹都可以認(rèn)為分為左路節(jié)點(diǎn),左路節(jié)點(diǎn)的右子樹。先訪問左路節(jié)點(diǎn),再來訪問左路節(jié)點(diǎn)的右子樹。把訪問左路節(jié)點(diǎn)的右子樹看成一個(gè)子問題,就可以完整遞歸訪問了2023-03-03STL priority_queue(優(yōu)先隊(duì)列)詳解
這篇文章主要介紹了 STL priority_queue(優(yōu)先隊(duì)列)詳解的相關(guān)資料,需要的朋友可以參考下2016-10-10C或C++報(bào)錯(cuò):ld returned 1 exit status報(bào)錯(cuò)的原因及解
這篇文章主要介紹了C或C++報(bào)錯(cuò):ld returned 1 exit status報(bào)錯(cuò)的原因及解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02