C語言文件操作入門指南
一、為什么使用文件
在學(xué)習(xí)完結(jié)構(gòu)體后,為了檢驗學(xué)習(xí)成果,我們寫了一個通訊錄的小程序,當通訊錄運行起來的時候,可以給通訊錄中增加、刪除數(shù)據(jù),此時數(shù)據(jù)是存放在內(nèi)存中的,當程序退出的時候,通訊錄中的數(shù)據(jù)就不存在了,等下次運行通訊錄程序的時候,數(shù)據(jù)又得重新錄入,如果使用這樣的通訊錄就很難受。
我們在想既然是通訊錄就應(yīng)該把信息記錄下來,只有我們自己選擇刪除數(shù)據(jù)的時候,數(shù)據(jù)才不復(fù)存在。
這就涉及到了數(shù)據(jù)持久化的問題,我們一般數(shù)據(jù)持久化的方法有,把數(shù)據(jù)存放在磁盤文件、存放到數(shù)據(jù)庫等方式。使用文件我們可以將數(shù)據(jù)直接存放在電腦的硬盤上,做到了數(shù)據(jù)的持久化。
二、什么是文件
- 磁盤上的文件是文件。
- 在程序設(shè)計中,我們一般談的文件有兩種:程序文件、數(shù)據(jù)文件(從文件功能的角度來分類的)。
2.1 程序文件
包括源程序文件(后綴為.c),目標文件(windows環(huán)境后綴為.obj),可執(zhí)行程序(windows環(huán)境后綴為.exe)。
2.2 數(shù)據(jù)文件
文件的內(nèi)容不一定是程序,而是程序運行時讀寫的數(shù)據(jù),比如程序運行需要從中讀取數(shù)據(jù)的文件,或者輸出內(nèi)容的文件。
??在前面我們所處理數(shù)據(jù)的輸入輸出都是以終端為對象的,即從終端的鍵盤輸入數(shù)據(jù),運行結(jié)果顯示到顯示器上。
??其實有時候我們會把信息輸出到磁盤上,當需要的時候再從磁盤上把數(shù)據(jù)讀取到內(nèi)存中使用,這里處理的就是磁盤上文件。
2.3 文件名
- 一個文件要有一個唯一的文件標識,以便用戶識別和引用
- 文件名包含3部分:文件路徑+文件名主干+文件后綴
- 例如: c:\code\test.txt
三、文件的打開和關(guān)閉
3.1 文件指針
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡稱“文件指針”。每個被使用的文件都在內(nèi)存中開辟了一個相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當前的位置等)。這些信息是保存在一個結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是有系統(tǒng)聲明的,取名FILE。
??例如,VS2013編譯環(huán)境提供的 stdio.h 頭文件中有以下的文件類型申明:
struct _iobuf { char* _ptr; int _cnt; char* _base; int _flag; int _file; int _charbuf; int _bufsiz; char* _tmpfname; }; typedef struct _iobuf FILE;
- 不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異。
- 每當打開一個文件的時候,系統(tǒng)會根據(jù)文件的情況自動創(chuàng)建一個FILE結(jié)構(gòu)的變量,并填充其中的信息,我們在使用時不必關(guān)心其細節(jié)。
- 一般都是通過一個FILE的指針來維護這個FILE結(jié)構(gòu)的變量,這樣使用起來更加方便。
?下面我們可以創(chuàng)建一個FILE*的指針變量:
FILE* pf;//文件指針變量
定義pf是一個指向FILE類型數(shù)據(jù)的指針變量。可以使pf指向某個文件的文件信息區(qū)(是一個結(jié)構(gòu)體變量)。通過該文件信息區(qū)中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它關(guān)聯(lián)的文件。
??比如:
3.2 文件的打開和關(guān)閉
文件在讀寫之前應(yīng)該先打開文件,在使用結(jié)束之后應(yīng)該關(guān)閉文件。
在編寫程序的時候,在打開文件的同時,都會返回一個FILE*的指針變量指向該文件,也相當于建立了指針和文件的關(guān)系。
ANSIC 規(guī)定使用fopen函數(shù)來打開文件,fclose來關(guān)閉文件:
//打開文件 FILE * fopen ( const char * filename, const char * mode ); //關(guān)閉文件 int fclose ( FILE * stream );
??????打開方式如下:
??示例代碼:
#include <stdio.h> int main() { //打開文件 FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //關(guān)閉文件 fclose(pf); pf == NULL; return 0; }
注意:我們平常所寫的程序保存數(shù)據(jù)是保存在內(nèi)存當中的,而我們想把內(nèi)存當中的數(shù)據(jù)放在文件當中去,文件又是在硬盤上的,所以把內(nèi)存當中的數(shù)據(jù)往硬盤上放的這個操作叫做寫文件或輸出操作,把文件當中的數(shù)據(jù)往內(nèi)存里邊放的操作叫讀文件或輸入操作。
四、文件的順序讀寫
??深入理解 “流”:
- 在C語言中,流可以分為文件流和輸入輸出流。
- 流是一個高度抽象的概念,我們可以把它理解為信息流或者水流,在寫文件的過程中,會有很多的數(shù)據(jù),這些數(shù)據(jù)可能會傳輸?shù)讲煌牡胤饺?,比如說顯示到屏幕上,存到硬盤上,傳到網(wǎng)絡(luò)上等等,這些統(tǒng)稱為外部設(shè)備,不同的外部設(shè)備操作方式也不同。
- 要把數(shù)據(jù)傳到各種外部設(shè)備上去,就對程序員有較高的要求了,這時候就有人想把這個過程簡化一下,在外部設(shè)備和數(shù)據(jù)之間抽象一個東西,這個東西我們就叫做流,它里邊流淌的都是數(shù)據(jù),程序員現(xiàn)在只關(guān)心把數(shù)據(jù)怎么放在流里邊,至于流怎么把數(shù)據(jù)放在外部設(shè)備上去,那就不是我們要操心的事兒了,這樣一來,整個過程就簡單了許多。
- 回憶一下我們曾經(jīng)用scanf從鍵盤上讀取數(shù)據(jù),或用printf向屏幕上打印數(shù)據(jù),直接就操作了,好像沒有打開鍵盤或打開屏幕的操作,這是因為C語言程序只要運行起來,就會默認打開三個流,分別為:標準輸入流 --- stdin、標準輸出流 --- stdout、標準錯誤流 --- stderr。因為scanf從鍵盤上讀取數(shù)據(jù)其實就是從標準輸入流里邊讀取數(shù)據(jù),而printf向屏幕上打印數(shù)據(jù)就是向標準輸出流里邊打印數(shù)據(jù),所以我們讀取數(shù)據(jù)或輸入數(shù)據(jù)的時候并沒有發(fā)現(xiàn)打開鍵盤或打開屏幕的操作。
- 文件流是用于文件讀寫操作的數(shù)據(jù)流,它可以從文件中讀取數(shù)據(jù),也可以向文件中寫入數(shù)據(jù),另外,文件流需要指定文件路徑和文件名,而標準輸出流不需要指定文件路徑,直接輸出到屏幕上。
??使用輸出流向屏幕輸出26個英文字母:
int main() { char ch = 0; for (ch = 'a'; ch < 'z'; ch++) { if (ch % 5 == 0) fputc('\n', stdout); fputc(ch, stdout); } return 0; }
??文件的順序讀寫函數(shù)介紹:
??fputc函數(shù):
1.函數(shù)原型:
int fputc ( int character, FILE * stream );
2.功能:
向指定的文件流中寫入一個字符。
3.示例:
int main() { //打開文件 FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } //寫文件 fputc('a', pf); fputc('b', pf); fputc('c', pf); fputc('d', pf); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
在上述程序中,剛開始我們打開一個文件,它里邊什么都沒有 ,但是我有一個文件指針是指向這個文件的起始位置的(這兒所說的文件指針是指標記字符位置的指針即光標,而不是pf);如果打開成功,接下來就要寫文件,最開始文件指針是指向第一個位置的,所以fputc把a寫了進去,這時候文件指針的狀態(tài)就會更新,指向a的后邊,然后fputc再把b寫進去,每一次進行寫操作后,文件指針的位置就要發(fā)生變化,直到把所有的字符都寫進去。然后fclose關(guān)閉文件,將文件保存起來。
??fgetc函數(shù):
1.函數(shù)原型:
int fgetc ( FILE * stream );
stream:要從中讀取字符的文件流。
2.功能:
從指定的文件流中讀取一個字符,并返回其ASCII值。
3.示例:
程序運行起來后,先打開文件,如果成功,就開始讀文件,讀文件的時候光標默認在最前面,當fgetc讀一個字符的時候,光標指向的那個位置為a,所以就返回字符a的ASCII值,然后打印在屏幕上,以同樣的步驟操作三次,就會將a、b、c分別打印在屏幕上,緊接著關(guān)閉文件。
??fputs函數(shù):
1.函數(shù)原型:
int fputs ( const char * str, FILE * stream );
str:要寫入文件的字符串。stream:要寫入的文件流。
2.功能:
向指定的文件流中寫入一行文本。
3.示例:
int main() { //打開文件 FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } //寫文件 //寫到文件中去 fputs("hello\n", pf); fputs("world!\n", pf); //寫到屏幕上去 fputs("hello\n", stdout); fputs("world!\n", stdout); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
??fgets函數(shù):
1.函數(shù)原型:
char * fgets ( char * str, int num, FILE * stream );
str:指向用于存儲讀取字符串的字符數(shù)組的指針。num:要讀取的最大字符數(shù)(num - 1個)。stream:要從中讀取行的文件流。
2.功能:
從指定的文件流中讀取一行文本,并將其存儲到指定的字符串中。
3.示例:
int main(){//打開文件FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");return 1;}//讀文件char arr[10] = { 0 };fgets(arr, 3, pf);//關(guān)閉文件fclose(pf);pf = NULL;return 0;}
因為它讀取的最大字符數(shù)是num - 1個,所以只存儲了前兩個字符。
??fprintf函數(shù):
1.函數(shù)原型:
int fprintf ( FILE * stream, const char * format, ... );
stream:要寫入數(shù)據(jù)的文件流。format:格式字符串,指定了要寫入的數(shù)據(jù)的格式。...:要寫入數(shù)據(jù)的變量列表。
2.功能:
向指定的文件流中按照指定格式寫入數(shù)據(jù)。
3.示例:
struct S { float f; char c; int n; }; int main() { struct S s = { 3.14f, 'w', 100 }; //打開文件 FILE* pf = fopen("test.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } //寫文件 fprintf(pf, "%f %c %d", s.f, s.c, s.n); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
??fscanf函數(shù):
1.函數(shù)原型:
int fscanf ( FILE * stream, const char * format, ... );stream:要從中讀取數(shù)據(jù)的文件流。format:格式字符串,指定了要讀取的數(shù)據(jù)的格式。...:要讀取的數(shù)據(jù)的變量列表。
2.功能:
從指定的文件流中按照指定的格式讀取數(shù)據(jù)。
3.示例:
struct S { float f; char c; int n; }; int main() { struct S s = { 0 }; //打開文件 FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } //寫文件 fscanf(pf, "%f %c %d", &(s.f), &(s.c), &(s.n)); printf("%f %c %d\n", s.f, s.c, s.n); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
??fwrite函數(shù):
1.函數(shù)原型:
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
- ptr:指向要寫入的數(shù)據(jù)的緩沖區(qū)的指針。
- size:每個數(shù)據(jù)的字節(jié)數(shù)。
- count:要寫入的數(shù)據(jù)塊的數(shù)量。
- stream:要寫入數(shù)據(jù)的文件流。
2.功能:
向指定的文件流中寫入指定數(shù)量的數(shù)據(jù)塊。
3.示例:
//二進制的方式寫進文件 int main() { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; //打開文件 FILE* pf = fopen("text.txt", "wb"); if (pf == NULL) { perror("fopen"); return 1; } //二進制的寫文件 fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
可以看到寫進去的值都變成了二進制,我們看不懂,但是我們也可以以二進制的方式讀取文件。
fread函數(shù):
1.函數(shù)原型:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
- ptr:指向存儲讀取數(shù)據(jù)的緩沖區(qū)的指針。
- size:每個數(shù)據(jù)的字節(jié)數(shù)。
- count:要讀取的數(shù)據(jù)塊的數(shù)量。
- stream:要讀取數(shù)據(jù)的文件流。
2.功能:
從指定的文件流中讀取指定數(shù)量的數(shù)據(jù)塊。
3.示例:
//二進制的方式讀取文件 int main() { int arr[10] = { 0 }; //打開文件 FILE* pf = fopen("text.txt", "rb"); if (pf == NULL) { perror("fopen"); return 1; } //二進制的讀文件 fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf); int i = 0; for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
??對比一組函數(shù):
scanf、fscanf、sscanf
printf、fprintf、sprintf
scanf是格式化的輸入函數(shù),針對的是標準輸入流 (鍵盤);printf是格式化的輸出函數(shù),針對的是標準輸出流(屏幕);綜上所述,scanf和printf是針對標準輸入/輸出流的格式化輸入/輸出函數(shù)。
fscanf是針對所有輸入流(文件流、標準輸入流)的格式化輸入函數(shù);sprintf是針對所有輸出流(文件流、標準輸出流)的格式化輸出函數(shù)。
sprintf是把格式化的數(shù)據(jù)轉(zhuǎn)化換成字符串;sscanf是將字符串轉(zhuǎn)換成格式化數(shù)據(jù)。
struct S { float f; char c; int n; }; int main() { struct S s = { 3.14f, 'c', 100 }; char arr[100] = { 0 }; sprintf(arr, "%f %c %d", s.f, s.c, s.n); printf("%s\n", arr); struct S tmp = { 0 }; sscanf(arr, "%f %c %d", &(tmp.f), &(tmp.c), &(tmp.n)); printf("%f\n", tmp.f); printf("%c\n", tmp.c); printf("%d\n", tmp.n); return 0; }
五、文件的隨機讀寫
5.1 fseek函數(shù):
1.函數(shù)原型:
int fseek ( FILE * stream, long int offset, int origin );
stream:指向FILE對象的指針,它標識了要定位的文件。
offset:偏移量,即要移動的字節(jié)數(shù)??梢詾檎龜?shù)、負數(shù)或0,具體取決于origin參數(shù)。
origin:定位的起始位置,可以是下列常量之一:
SEEK_SET:從文件開頭開始偏移。SEEK_CUR:從當前位置開始偏移。SEEK_END:從文件末尾開始偏移。
返回值:如果定位成功,fseek函數(shù)返回0;如果失敗,返回非零值。
2.功能:
fseek函數(shù)用于設(shè)置文件位置指針,以便在文件中進行定位。它可以將文件位置指針設(shè)置到文件的任意位置,從而可以進行讀取或?qū)懭氩僮鳌?/p>
3.示例:
int main() { //打開文件 FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = fgetc(pf); printf("%c\n", ch);//a ch = fgetc(pf); printf("%c\n", ch);//b //ch = fgetc(pf); //printf("%c\n", ch);//c //fseek(pf, -2, SEEK_CUR);//從當前位置開始偏移 //fseek(pf, 0, SEEK_SET);//從文件的開頭開始偏移 fseek(pf, -6, SEEK_END);//從文件的末尾開始偏移 ch = fgetc(pf); printf("%c\n", ch);//a //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
我的文件中放著一串字符串“abcdef”, 現(xiàn)在我想從中讀取字符出來,用fgetc函數(shù)就可以,但我想讓它第三個字符讀的是a,這個時候就可以用fseek函數(shù)。
5.2 ftell函數(shù):
1.函數(shù)原型:
long int ftell ( FILE * stream );stream:指向FILE對象的指針,用于標識要獲取位置的文件。返回值:返回當前位置相對于文件開頭的偏移量,如果出現(xiàn)錯誤則返回-1。
2. 功能:
用于獲取文件位置指針的當前位置,即返回當前位置相對于文件開頭的偏移量。
3.示例:
int main() { //打開文件 FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = fgetc(pf); printf("%c\n", ch);//a ch = fgetc(pf); printf("%c\n", ch);//b ch = fgetc(pf); printf("%c\n", ch);//c int pos = ftell(pf); printf("pos= %d\n", pos); //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
5.3 rewind函數(shù):
1. 函數(shù)原型:
void rewind ( FILE * stream ); stream:指向FILE對象的指針,用于標識要重新定位的文件。
2.功能:
用于將文件位置指針重新定位到文件的開頭,即相當于調(diào)用fseek(stream, 0, SEEK_SET)。
3.示例:
int main() { //打開文件 FILE* pf = fopen("text.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int ch = fgetc(pf); printf("%c\n", ch);//a ch = fgetc(pf); printf("%c\n", ch);//b //ch = fgetc(pf); //printf("%c\n", ch);//c rewind(pf); ch = fgetc(pf); printf("%c\n", ch);//a //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
六、文本文件和二進制文件
- 根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件被稱為文本文件或者二進制文件。
- 數(shù)據(jù)在內(nèi)存中以二進制的形式存儲,如果不加轉(zhuǎn)換的輸出到外存,就是二進制文件。
- 如果要求在外存上以ASCII碼的形式存儲,則需要在存儲前轉(zhuǎn)換。以ASCII字符的形式存儲的文件就是文本文件。
那一個數(shù)據(jù)在內(nèi)存中是怎么存儲的呢?
字符一律以ASCII形式存儲,數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲,也可以使用二進制形式存儲。如有整數(shù)10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個字節(jié)(每個字符一個字節(jié)),而以二進制形式輸出,則在磁盤上只占4個字節(jié)(VS2013測試)。
??測試代碼:
我們將10000以 二進制的形式寫到文件中,就是上述效果,我們自己是看不懂的,但VS卻能看懂,具體操作步驟如下圖:
int main() { int a = 10000; FILE* pf = fopen("test.txt", "wb"); //二進制的形式寫到文件中 fwrite(&a, 4, 1, pf); fclose(pf); pf = NULL; return 0; }
將10000轉(zhuǎn)換成二進制為 0010 0111 0001 0000,這是16個二進制位,不夠32位,我們給它補齊0000 0000 0000 0000 0010 0111 0001 0000,每4個二進制位轉(zhuǎn)換成1個16進制位,就為0x00 0x00 0x27 0x10,那在內(nèi)存中以小端方式存放就為10 27 00 00。
七、文件讀取結(jié)束的判定
7.1 文本文件的讀取結(jié)束判定
文本文件讀取是否結(jié)束,判斷返回值是否為 EOF ( fgetc ),或者 NULL ( fgets )。fgetc 判斷是否為 EOF 。fgets 判斷返回值是否為 NULL。
ferror:在文件讀取結(jié)束后,用來判斷文件是否因為讀取過程中遇到錯誤而結(jié)束。feof:在文件讀取結(jié)束后,用來判斷文件是否因為讀取過程中遇到文件結(jié)束標志而結(jié)束。牢記:在文件讀取過程中,不能用feof函數(shù)的返回值直接用來判斷文件是否結(jié)束。而是應(yīng)用于當文件讀取結(jié)束的時候,判斷是讀取失敗結(jié)束,還是遇到文件尾結(jié)束 。
示例:
#include <stdio.h> #include <stdlib.h> int main() { int c; // 注意:是int而非char,因為要求處理EOF,而EOF實際是-1,是個整型值 FILE* fp = fopen("test.txt", "r"); if (!fp) { perror("fopen"); return 1; } //fgetc 當讀取失敗的時候或者遇到文件結(jié)束的時候,都會返回EOF while ((c = fgetc(fp)) != EOF) // 標準C I/O讀取文件循環(huán) { putchar(c); } //判斷是什么原因結(jié)束的 if (ferror(fp)) puts("I/O error when reading"); else if (feof(fp)) puts("End of file reached successfully"); fclose(fp); }
7.2 二進制文件的讀取結(jié)束判定
fread函數(shù)判斷返回值是否小于實際要讀的個數(shù)。
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );fread要求讀取count個大小為size字節(jié)的數(shù)據(jù)。如果真的讀取到count個數(shù)據(jù),函數(shù)返回count。如果沒有讀取到count個數(shù)據(jù),返回的是真實讀取到的完整的數(shù)據(jù)個數(shù)。
示例:
#include <stdio.h> enum { SIZE = 5 }; int main() { double a[SIZE] = { 1.,2.,3.,4.,5. }; FILE* fp = fopen("test.bin", "wb"); // 必須用二進制模式 fwrite(a, sizeof * a, SIZE, fp); // 寫 double 的數(shù)組 fclose(fp); double b[SIZE]; fp = fopen("test.bin", "rb"); size_t ret_code = fread(b, sizeof * b, SIZE, fp); // 讀 double 的數(shù)組 if (ret_code == SIZE) { puts("Array read successfully, contents: "); for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]); putchar('\n'); } else { // error handling if (feof(fp)) printf("Error reading test.bin: unexpected end of file\n"); else if (ferror(fp)) { perror("Error reading test.bin"); } } fclose(fp); return 0; }
八、文件緩沖區(qū)
ANSIC 標準采用“緩沖文件系統(tǒng)”處理數(shù)據(jù)文件,所謂緩沖文件系統(tǒng)是指系統(tǒng)自動地在內(nèi)存中為程序中每一個正在使用的文件開辟一塊“文件緩沖區(qū)”。從內(nèi)存向磁盤輸出數(shù)據(jù)會先送到內(nèi)存中的緩沖區(qū),裝滿緩沖區(qū)后才一起送到磁盤上。如果從磁盤向計算機讀入數(shù)據(jù),則從磁盤文件中讀取數(shù)據(jù)輸入到內(nèi)存緩沖區(qū)(充滿緩沖區(qū)),然后再從緩沖區(qū)逐個地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等),緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定。
#include <stdio.h> #include <windows.h> //VS2019 WIN10環(huán)境測試 int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcdef", pf);//先將代碼放在輸出緩沖區(qū) printf("睡眠10秒-已經(jīng)寫數(shù)據(jù)了,打開test.txt文件,發(fā)現(xiàn)文件沒有內(nèi)容\n"); Sleep(10000); printf("刷新緩沖區(qū)\n"); fflush(pf);//刷新緩沖區(qū)時,才將輸出緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒-此時,再次打開test.txt文件,文件有內(nèi)容了\n"); Sleep(10000); fclose(pf); //注:fclose在關(guān)閉文件的時候,也會刷新緩沖區(qū) pf = NULL; return 0; }
通過以上測試,可以得出一個結(jié)論:
因為有緩沖區(qū)的存在,C語言在操作文件的時候,需要做刷新緩沖區(qū)或者在文件操作結(jié)束的時候關(guān)閉文件。如果不做,可能導(dǎo)致讀寫文件的問題。
相關(guān)文章
C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享
這篇文章主要介紹了C語言實現(xiàn)的統(tǒng)計素數(shù)并求和代碼分享,來自PAT平臺(浙江大學(xué)計算機程序設(shè)計能力考試系統(tǒng))的一個題目,需要的朋友可以參考下2014-08-08Vscode搭建遠程c開發(fā)環(huán)境的圖文教程
很久沒有寫C語言了,今天抽空學(xué)習(xí)下C語言知識,接下來通過本文給大家介紹Vscode搭建遠程c開發(fā)環(huán)境的詳細步驟,本文通過圖文實例代碼相結(jié)合給大家介紹的非常詳細,需要的朋友參考下吧2021-11-11