C語言實(shí)現(xiàn)文件讀寫操作的幾種常用方法
一 、文件讀寫的常用函數(shù)
(1) 讀寫文本文件:
讀文本文件 :一般都使用 getc 、fgets 、fscanf 函數(shù)
使用getc讀文件
#include <stdio.h> int main() { char a[20] = "a.txt"; FILE *p = fopen(a,"r"); if(p) { char c; while(1) { c = getc(p); if(c == EOF) break; printf("%c",c); } printf("\n"); fclose(p); } else { printf("fail\n"); } return 0; }
使用fgets讀文件
#include <stdio.h> int main() { FILE *p = fopen("test.txt","r"); if(p == NULL) return 0; char temp[1024]; fgets(temp,sizeof(temp),p); while(!feof(p)) { printf("%s",temp); fgets(temp,sizeof(temp),p); } fclose(p); return 0; }
使用fscanf讀文件
#include <stdio.h> int main() { FILE *p = fopen("a.txt", "r"); if(p == NULL) { printf("the file is close!"); return 0; } char str1[200], str2[200], str3[200]; int year; int status = fscanf(p, "%s %s %s %d", str1, str2, str3, &year); while(!feof(p)) { printf("%s %s %d %d status = %d\n", str1, str2, str3, year, status); status = fscanf(p, "%s %s %s %d", str1, str2, str3, &year); } fclose(p); return 0; }
寫文本文件 :一般都使用 putc 、 fputs、fprintf 函數(shù)
使用putc寫文件
#include <stdio.h> int main() { FILE *p = fopen("a.txt","w"); if(p) { putc('h',p); fclose(p); } return 0; }
使用fputs寫文件
#include <stdio.h> int main() { FILE *p = fopen("abc.c","w"); if(p) { fputs("#include <stdio.h>\nint main()\n{\nprintf(\"hello world\\n\");\nreturn 0;\n}",p); fclose(p); } return 0; }
使用fprintf寫文件
#include <stdio.h> #include <string.h> int main() { FILE *p = fopen("a.txt","w"); char buf[1024]; fgets(buf, sizeof(buf), stdin); while(strcmp(buf,"exit\n") != 0) { fprintf(p, "%s", buf); fgets(buf, sizeof(buf), stdin); } fclose(p); return 0; }
(2) 讀寫二進(jìn)制文件
讀二進(jìn)制文件: 使用fread 函數(shù)
代碼:
#include <stdio.h> void readFile() { FILE *p = fopen("a.txt", "rb"); char buf[20] = { 0 }; int index = 0; while(1) { int res = fread(buf, 1, 5, p); printf("res = %d , ", res); if(feof(p)) break; printf("buf = %s\n",buf); index++; } fclose(p); printf("%d\n", index); } int main() { readFile(); return 0; }
寫二進(jìn)制文件: 使用fwrite 函數(shù)
代碼
#include <stdio.h> void writeFile() { FILE *p = fopen("b.txt", "w"); char buf = 'a'; int i; for(i = 0; i < 10 ; i++) { fwrite(&buf, 1, 1, p); buf++; } fclose(p); } int main() { writeFile(); return 0; }
二、文件讀寫的深層次的剖析
(1)操作系統(tǒng)與硬件儲(chǔ)存
眾所周知,我們的計(jì)算機(jī)操作系統(tǒng)都是由C語言寫的,通過C語言協(xié)調(diào)物理內(nèi)存與虛擬內(nèi)存,操作系統(tǒng)想要向物理內(nèi)存中寫數(shù)據(jù)的時(shí)候,會(huì)費(fèi)很大的力。
寫數(shù)據(jù)到物理內(nèi)存
當(dāng)操作系統(tǒng)有一個(gè)字節(jié)的數(shù)據(jù)想要寫入物理磁盤中,首先要經(jīng)歷一下幾個(gè)步驟:
- 調(diào)用CPU的控制器,發(fā)出存儲(chǔ)請(qǐng)求。
- 控制器把將要存儲(chǔ)的數(shù)據(jù)放入臨時(shí)寄存器。
- 查看總線是否被占用,請(qǐng)求總線控制。
- 往地址總線發(fā)送將要使用的一個(gè)字節(jié)的空間指定。
- 講數(shù)據(jù)寄存器中數(shù)據(jù)發(fā)送到數(shù)據(jù)總線上,傳輸?shù)较纫徊秸业降奈锢淼刂贰?/li>
- 存儲(chǔ)完畢,釋放總線。
從磁盤中讀數(shù)據(jù)
讀數(shù)據(jù)的操作與寫數(shù)據(jù)的操作正好相反,也是要經(jīng)歷總線請(qǐng)求與總線釋放的過程。
總之,操作系統(tǒng)想要往磁盤中讀寫數(shù)據(jù)要經(jīng)歷很繁瑣的過程。
(2)操作系統(tǒng)封裝讀寫數(shù)據(jù)函數(shù)接口
每次操作系統(tǒng)與磁盤進(jìn)行數(shù)據(jù)交互的時(shí)候,都會(huì)對(duì)CPU有一系列的操作指令,這些讀寫指令的合集就是讀寫函數(shù),通過C語言實(shí)現(xiàn)這些讀寫函數(shù)再往外部拋出一系列的接口,就實(shí)現(xiàn)的讀寫數(shù)據(jù)的函數(shù)封裝。
當(dāng)用戶想往磁盤中寫入數(shù)據(jù)的時(shí)候只需要調(diào)用這些函數(shù)接口就行了。
然而這些函數(shù)都是針對(duì)最底層的數(shù)據(jù)存儲(chǔ)操作,不利于計(jì)算機(jī)的操作性能提高,所以,有人就在這層函數(shù)的基礎(chǔ)上再次進(jìn)行封裝,把性能更加好,更加優(yōu)化的讀寫數(shù)據(jù)函數(shù)封裝到C語言的標(biāo)準(zhǔn)庫中。
在標(biāo)準(zhǔn)庫中的讀寫數(shù)據(jù)函數(shù),例如fwrite和fputs等等。它們不是每次寫入一個(gè)字節(jié)數(shù)據(jù)就往物理磁盤中寫入數(shù)據(jù),而是利用函數(shù)在內(nèi)存中開辟出一個(gè)固定大小的字節(jié)緩沖池,通過這個(gè)緩沖池,來實(shí)現(xiàn)數(shù)據(jù)的讀與寫。
(3)C語言中的數(shù)據(jù)緩沖池
C語言的所有讀寫函數(shù),都會(huì)使用到數(shù)據(jù)緩沖池,無論是讀數(shù)據(jù)操作,還是寫數(shù)據(jù)操作,都會(huì)把數(shù)據(jù)臨時(shí)存儲(chǔ)到這里。
寫數(shù)據(jù)
當(dāng)我們使用C語言往文件中寫入一個(gè)字節(jié)的數(shù)據(jù)的時(shí)候,會(huì)經(jīng)歷一下幾個(gè)步驟:
- 使用函數(shù)往目標(biāo)文件中寫入一個(gè)字節(jié)的數(shù)據(jù)。
- 數(shù)據(jù)被存儲(chǔ)在內(nèi)存的數(shù)據(jù)緩沖池中。
- 關(guān)閉要寫入的文件。
- 底層函數(shù)把緩沖池中的數(shù)據(jù)寫入磁盤中。
從上面的步驟中可以看出我們的函數(shù)在執(zhí)行到寫入數(shù)據(jù)的操作的時(shí)候,數(shù)據(jù)并沒有真正的寫入到磁盤中,而是等到寫入文件的操作結(jié)束的時(shí)候,才把數(shù)據(jù)緩沖池中的數(shù)據(jù)寫入磁盤中。
同樣的我們使用C語言讀一個(gè)字節(jié)數(shù)據(jù)的時(shí)候,同樣會(huì)經(jīng)歷一下步驟:
- 打開要讀的文件。
- 底層函數(shù)從磁盤中讀取滿整個(gè)緩沖池的數(shù)據(jù)。
- 關(guān)閉要讀的文件。
- 從緩沖池中讀取要讀取的字節(jié)數(shù),剩余沒用的數(shù)據(jù)不讀。
緩沖池工作原理
當(dāng)知道我們的所有讀寫操作都要進(jìn)入緩沖池時(shí),我們同樣要知道緩沖池的工作原理。
- 緩沖池有一定固定的大小
- 緩沖池在進(jìn)行讀數(shù)據(jù)的操作時(shí),如果要讀取的數(shù)據(jù)字節(jié)小于緩沖池的大小,緩沖池會(huì)從磁盤中讀取滿整個(gè)緩沖池的數(shù)據(jù),所以當(dāng)每次讀取的字節(jié)數(shù)過小,讀取次數(shù)過多的時(shí)候,會(huì)減少訪問實(shí)際磁盤的磁盤,增加程序運(yùn)行的性能。
- 緩沖池的刷新,每刷新一次都會(huì)進(jìn)行與實(shí)際物理內(nèi)存的交互。
當(dāng)緩沖池滿了或者目標(biāo)操作文件關(guān)閉的時(shí)候,緩沖池會(huì)自動(dòng)刷新,寫數(shù)據(jù)時(shí),緩沖池的數(shù)據(jù)會(huì)進(jìn)入物理磁盤;讀數(shù)據(jù)時(shí),緩沖池的數(shù)據(jù)會(huì)數(shù)據(jù)固定字節(jié)的數(shù)據(jù)進(jìn)入輸出終端。
總而言之,緩沖池僅僅是用戶與物理磁盤之間數(shù)據(jù)交戶的一個(gè)緩沖而已,不用想的太深?yuàn)W。
三、使用函數(shù)刷新緩沖池
fflush函數(shù):
函數(shù)作用:
刷新緩沖池
函數(shù)定義:
int fflush(FILE *P);
參數(shù) 返回值:
- P:目標(biāo)操作文件
- 返回值:如果成功,該函數(shù)返回零值。如果發(fā)生錯(cuò)誤,則返回 EOF 。
使用示例:
現(xiàn)有空文件a.txt
利用標(biāo)準(zhǔn)輸入數(shù)據(jù),在文件沒有關(guān)閉的時(shí)候,查看文件內(nèi)是否有寫入的數(shù)據(jù)。
#include <stdio.h> #include <string.h> void write_file() { FILE *p = fopen("a.txt", "w"); char temp[100] = { 0 }; while(1) { fgets(temp, sizeof(temp), stdin); if(strcmp(temp, "exit\n") == 0) break; fprintf(p, "%s", temp); } fclose(p); } int main() { write_file(); return 0; }
運(yùn)行結(jié)果:
輸入中
[文件]$ gcc -o a fflush.c
[文件]$ a
hello
查看文件a.txt
可以看到文件為空,輸入的文件現(xiàn)在正存儲(chǔ)在緩沖池中。
輸入exit退出輸入,查看文件a
[文件]$ cat a.txt
hello
文件關(guān)閉,緩沖池中的數(shù)據(jù)寫入磁盤。
現(xiàn)在我們創(chuàng)建一個(gè)函數(shù)使每輸入一次都寫入一次磁盤:
#include <stdio.h> #include <string.h> void write_file() { FILE *p = fopen("a.txt", "w"); char temp[100] = { 0 }; while(1) { fgets(temp, sizeof(temp), stdin); if(strcmp(temp, "exit\n") == 0) break; fprintf(p, "%s", temp); fflush(p); } fclose(p); } int main() { write_file(); return 0; }
運(yùn)行結(jié)果:
輸入中,查看a.txt
[文件]$ gcc -o a fflush.c
[文件]$ a
hello
再開啟另一個(gè)終端查看文件 a.txt 狀態(tài):
[文件]$ cat a.txt
hello
輸入結(jié)束,查看a.txt
[文件]$ a
hello
exit
[文件]$ cat a.txt
hello
[文件]$
可以看到使用fflush函數(shù)把緩沖池中的數(shù)據(jù)寫入了磁盤。
四、總結(jié)
當(dāng)我們?cè)谕疟P中錄入重要的非常重要的數(shù)據(jù)的時(shí)候,一定要使用fflush不斷的刷新緩沖池,因?yàn)閿?shù)據(jù)非常重要;但我們輸入不重要的數(shù)據(jù)是一定要盡量減少使用fflush函數(shù)的次數(shù),因?yàn)槟菢訒?huì)讓程序變得緩慢。
到此這篇關(guān)于C語言實(shí)現(xiàn)文件讀寫操作的幾種常用方法的文章就介紹到這了,更多相關(guān)C語言 文件讀寫操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VC獲取當(dāng)前路徑及程序名的實(shí)現(xiàn)代碼
VC上或取當(dāng)前路徑有多種方法,最常用的是使用 GetCurrentDirectory和GetModuleFileName函數(shù),個(gè)中都有諸多注意事項(xiàng),特別總結(jié)一下2016-11-11C語言模擬實(shí)現(xiàn)strstr函數(shù)的示例代碼
strstr是C語言中的函數(shù),作用是返回字符串中首次出現(xiàn)子串的地址。本文將用C語言模擬實(shí)現(xiàn)strstr函數(shù),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-07-07C++ STL入門教程(3) deque雙向隊(duì)列使用方法
這篇文章主要為大家詳細(xì)介紹了C++ STL入門教程第三篇,deque雙向隊(duì)列的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08C語言實(shí)現(xiàn)手寫Map(全功能)的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用C語言實(shí)現(xiàn)手寫Map(全功能),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語言有一定幫助,需要的可以參考一下2022-08-08C語言結(jié)構(gòu)體內(nèi)存對(duì)齊問題小結(jié)
本文主要講解了C語言中結(jié)構(gòu)體的內(nèi)存對(duì)齊規(guī)則、計(jì)算方法以及影響因素,包括對(duì)齊規(guī)則的四個(gè)要點(diǎn)、內(nèi)存對(duì)齊的原因、如何修改默認(rèn)對(duì)齊數(shù)以及結(jié)構(gòu)體傳參時(shí)的注意事項(xiàng),此外,還介紹了結(jié)構(gòu)體位段的概念、內(nèi)存分配和使用注意事項(xiàng),感興趣的朋友一起看看吧2025-02-02C語言詳細(xì)分析講解內(nèi)存管理malloc realloc free calloc函數(shù)的使用
C語言內(nèi)存管理相關(guān)的函數(shù)主要有realloc、calloc、malloc、free等,下面這篇文章主要給大家介紹了關(guān)于C語言內(nèi)存管理realloc、calloc、malloc、free函數(shù)的相關(guān)資料,需要的朋友可以參考下2022-05-05