C語言文件操作的入門詳解教程
一.一些需要掌握的知識(shí)點(diǎn)
文件有千千萬萬,但是在我們的程序設(shè)計(jì)當(dāng)中,我們談的文件一般有兩種:
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)容的文件。
而在本節(jié)中,我們主要提到的是數(shù)據(jù)文件。
1.文件名
我們知道,名字都是用來標(biāo)識(shí)和區(qū)別事物的,那么文件名也是這樣,是區(qū)別各個(gè)文件的標(biāo)識(shí)。
一個(gè)文件名要包含 3 個(gè)部分:文件路徑+文件名主干+文件后綴
如:C:\Windows\System32\drivers\etc.txt
其中 :C:\Windows\System32\drivers\ 是文件路徑,etc 是文件名主干,txt 是文件名后綴。
當(dāng)然了,各個(gè)平臺(tái)的文件路徑并不相同,以及為了方便起見文件標(biāo)識(shí)通常別稱為文件名
2.文件類型
根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件被稱為文本文件或者二進(jìn)制文件。
二進(jìn)制文件:數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ),并不加轉(zhuǎn)換的輸出到外存。
文本文件:要求在外存上以ASCII碼的形式存儲(chǔ),需要在存儲(chǔ)前轉(zhuǎn)換,以ASCII字符的形式存儲(chǔ)的文件。
那么一個(gè)數(shù)據(jù)在內(nèi)存中是怎樣存儲(chǔ)的呢?
字符一律以ASCII形式存儲(chǔ),數(shù)值型數(shù)據(jù)既可以用ASCII形式存儲(chǔ),也可以使用二進(jìn)制形式存儲(chǔ)。
如有整數(shù)10000,如果以ASCII碼的形式輸出到磁盤,則磁盤中占用5個(gè)字節(jié)(每個(gè)字符一個(gè)字節(jié))
而二進(jìn)制形式輸出,則在磁盤上只占4個(gè)字節(jié)(VS2019測(cè)試)。
如:
我們可以測(cè)試一番:
#include <stdio.h> int main() { int a = 10000; FILE* pf = fopen("test.txt", "wb"); fwrite(&a, 4, 1, pf);//二進(jìn)制的形式寫到文件中 fclose(pf); pf = NULL; return 0; }
我們打開的時(shí)候要注意以二進(jìn)制編輯器來打開,你會(huì)發(fā)現(xiàn)出現(xiàn)了如下圖顯示的一串?dāng)?shù)字,其中它們是以十六進(jìn)制現(xiàn)實(shí)的,轉(zhuǎn)換一下,剛好是上圖顯示的那串二進(jìn)制數(shù)字(注意VS采用的是小端儲(chǔ)存模式)
3.數(shù)據(jù)流
數(shù)據(jù)流:
指程序于數(shù)據(jù)的交互是以流的形式進(jìn)行的,包括輸入流與輸出流;
輸入流:
程序從輸入流讀取數(shù)據(jù)源。數(shù)據(jù)源包括鍵盤,文件,網(wǎng)絡(luò)等,即:將數(shù)據(jù)源讀入到程序的外界通道。
輸出流:
程序向輸出流寫入數(shù)據(jù)。將程序中的數(shù)據(jù)輸出到外界(顯示器,打印機(jī),文件,網(wǎng)絡(luò),等)的通信通道。
采用數(shù)據(jù)流的目的:使得輸入輸出獨(dú)立于設(shè)備,不關(guān)心數(shù)據(jù)源來自何方,也不管輸出的目的地是何種設(shè)備。
4.文件緩沖區(qū)
緩沖區(qū):
指在程序運(yùn)行時(shí),所提供的額外內(nèi)存,可用來暫時(shí)存放做準(zhǔn)備執(zhí)行的數(shù)據(jù)。它可在創(chuàng)建、訪問、刪除靜態(tài)數(shù)據(jù)上,大大提高運(yùn)行速度(速度的提高程度有時(shí)甚至可高達(dá)幾十倍),
為我們提供了極大的便捷,節(jié)省了大量的時(shí)間與精力
文件緩沖區(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ū)),
然后再?gòu)木彌_區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)。緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定的。
如:
無論是輸入輸出,都先在緩沖區(qū)里存著,然后在進(jìn)行輸入輸出。
5.文件指針
緩沖文件系統(tǒng)中,關(guān)鍵的概念是“文件類型指針”,簡(jiǎn)稱“文件指針”。
每個(gè)被使用的文件都在內(nèi)存中開辟了一個(gè)相應(yīng)的文件信息區(qū),用來存放文件的相關(guān)信息(如文件的名字,文件狀態(tài)及文件當(dāng)前的位置等)。
這些信息是保存在一個(gè)結(jié)構(gòu)體變量中的。該結(jié)構(gòu)體類型是有系統(tǒng)聲明的,取名FILE。
我們可以來看在VS 2019中FILE的聲明:
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // Stream I/O Declarations Required by this Header // //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ #ifndef _FILE_DEFINED #define _FILE_DEFINED typedef struct _iobuf { void* _Placeholder; } FILE; #endif
不同的C編譯器的FILE類型包含的內(nèi)容不完全相同,但是大同小異。
每當(dāng)打開一個(gè)文件的時(shí)候,系統(tǒng)會(huì)根據(jù)文件的情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,并填充其中的信息,使用者不必關(guān)心細(xì)節(jié)。
一般都是通過一個(gè)FILE的指針來維護(hù)這個(gè)FILE結(jié)構(gòu)的變量,這樣使用起來更加方便。
如下:我們便創(chuàng)建了一個(gè)文件指針
FILE* pf;//文件指針變量
定義pf是一個(gè)指向FILE類型數(shù)據(jù)的指針變量??梢允筽f指向某個(gè)文件的文件信息區(qū)(是一個(gè)結(jié)構(gòu)體變量)。
通過該文件信息區(qū)中的信息就能夠訪問該文件。也就是說,通過文件指針變量能夠找到與它關(guān)聯(lián)的文件。
比如:
到此,我們的基本概念就結(jié)束了,下面進(jìn)入到函數(shù)部分:
二.與文件操作相關(guān)的一些函數(shù)
1.文件的打開及關(guān)閉
文件在使用前,我們肯定要打開文件;在使用結(jié)束后,我們需要關(guān)閉文件。
1.fopen() --- 文件打開函數(shù)
聲明:文檔
FILE* fopen(const char* filename, const char* mode);
參數(shù):
const char* filename ---- 文件名
const char* mode ---- 文件打開方式
文件打開方式:
那,接下來看一個(gè)實(shí)例:
/* fopen example */ #include <stdio.h> int main() { FILE* pFile; pFile = fopen("myfile.txt", "w");//打開一個(gè)文件(沒有就創(chuàng)建),以寫的方式打開 if (pFile != NULL)//如果打開成功 { fputs("fopen example", pFile);//就往文件里寫入 fopen example fclose(pFile);//關(guān)閉文件 } return 0; }
2.fclose() --- 文件關(guān)閉函數(shù)
聲明:文檔
int fclose(FILE* stream);
參數(shù)為要關(guān)閉文件的文件指針
示例:
int main() { //相對(duì)路徑 //.. 表示上一級(jí)目錄 //. 當(dāng)前目錄 //FILE* pf = fopen("../data.txt", "r");//在上一級(jí)文件中打開data.txt,如果沒有就報(bào)錯(cuò) //絕對(duì)路徑 C:\Windows\System32\drivers\etc.txt //./hehe/test.txt //../../ FILE* pf = fopen("../../data.txt", "r"); if (pf == NULL) { printf("打開文件失敗\n"); printf("%s\n", strerror(errno));//注意頭文件的包含 stding.h errno.h return 1;//失敗返回 } //打開文件成功 printf("打開文件成功\n"); //讀寫文件 //... //關(guān)閉文件 fclose(pf); pf = NULL;//及時(shí)置NULL return 0; }
注:
其他的文件打開模式,將在函數(shù)講解的時(shí)候一并講解:
2.文件的順序讀寫
1. 字符輸入輸出函數(shù)
fput--- 向指定輸出流輸出一個(gè)字符聲明
int fputc ( int character, FILE * stream );
參數(shù):
int character --- 所輸入的字符
FILE * stream --- 指定輸出流
fgetc--- 向指定輸入流輸入一個(gè)字符聲明
int fgetc ( FILE * stream );
參數(shù):
FILE * stream --- 指定輸入流
示例 1:
//在文件里寫入a-z26個(gè)字母 int main() { //fopen函數(shù)如果是以寫的形式打開 //如果文件不錯(cuò)在,會(huì)創(chuàng)建這個(gè)文件 //如果文件存在,會(huì)清空文件的內(nèi)容 //fopen函數(shù)如果是以讀的形式打開 //文件不存在打開失敗 FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1;//失敗返回 } //寫文件 int i = 0; for (i = 'a'; i <= 'z'; i++) { fputc(i, pf);//在文件里寫 --- pf 我們自己定義的文件指針 fputc(i, stdout);//顯示在屏幕上 --- stdout --- 標(biāo)準(zhǔn)輸出流 } // 從鍵盤輸入 --- stdin --- 標(biāo)準(zhǔn)輸入流 //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
這里需要注意的就是所指定的輸出流:
在C語言所寫的程序運(yùn)行起來時(shí),會(huì)默認(rèn)打開三個(gè)流:
1.stdin - 標(biāo)準(zhǔn)輸入流 (鍵盤)
2.stdout - 標(biāo)準(zhǔn)輸出流 (屏幕)
3.stderr - 標(biāo)準(zhǔn)錯(cuò)誤流(屏幕)
示例 2:
//從剛才寫的文件,再把內(nèi)容讀出來 int main() { FILE* pf = fopen("data.txt", "r");// r 是以讀的形式打開文件,如果沒有該文件就報(bào)錯(cuò) if (pf == NULL) { printf("%s\n", strerror(errno)); 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 //ch = fgetc(pf); //printf("%c\n", ch);//d int ch = 0; while ((ch = fgetc(pf)) != EOF)// pf --- 所指定的輸入流 { printf("%c ", ch); } //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
這里需要注意一點(diǎn):
fgetc() 的返回值:我們?cè)谶@就只說出現(xiàn)錯(cuò)誤的信息:
If the position indicator was at theend-of-file, the function returnsEOFand sets theeof indicator(feof) ofstream.
If some other reading error happens, the function also returnsEOF, but sets itserror indicator(ferror) instead.
翻譯過來就是:
如果文件指針處于文件末端,則函數(shù)返回EOF,并設(shè)置流的eof指示器(feof)
如果發(fā)生其他讀數(shù)錯(cuò)誤,函數(shù)也會(huì)返回EOF,但會(huì)設(shè)置錯(cuò)誤指示器(ferror)
這里的feof和ferror我們專門會(huì)放到最后講
2.文本行輸入輸出函數(shù)
fputs--- 文本行輸出行數(shù)聲明
int fputs ( const char * str, FILE * stream );
參數(shù):
const char * str --- 將被寫入輸出流的字符指針
FILE * stream --- 輸出流
fgets--- 文本行輸入函數(shù)聲明
char * fgets ( char * str, int num, FILE * stream );
參數(shù):
char * str --- 所輸入信息的存放位置
int num --- 要讀內(nèi)容的大小
FILE * stream --- 輸入流
示例 1:
int main() { FILE* pf = fopen("data.txt", "a");// a --- 如果沒有就該文件就創(chuàng)建,有就在該文件后方繼續(xù)追加內(nèi)容 if (pf == NULL) // 而 w 如果存在該文件會(huì)覆蓋重寫 { printf("%s\n", strerror(errno)); return 1; } //寫一行數(shù)據(jù) fputs("hello\n", pf);//輸出到文件中 fputs("hello\n", stdout);//在屏幕上顯示 fputs("hello world\n", pf);//輸出到文件中 fputs("hello world\n",stdout);//在屏幕上顯示 fclose(pf); pf = NULL; return 0; }
示例 2:
int main() { char arr[100] = {0};//存放寫入的信息 FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1; } //讀一行數(shù)據(jù) //fgets(arr, 100, pf); //printf("%s\n", arr); while (fgets(arr, 10, pf) != NULL)//輸出---一次讀十個(gè) { printf("%s", arr); } //fgets從標(biāo)準(zhǔn)輸入流中讀取 fgets(arr, 100, stdin); printf("%s\n", arr); fclose(pf); pf = NULL; return 0; }
注意:
1.在fgets中num的大小數(shù)包含 \0 ,在內(nèi)的,如果所輸入的內(nèi)容大小大于指定的大小,fgets會(huì)強(qiáng)行截?cái)嗉?\0.
2.返回值的處理:
If theend-of-fileis encountered while attempting to read a character, theeof indicatoris set (feof). If this happens before any characters could be read, the pointer returned is a null pointer
(andthe contentsofstrremain unchanged).
If a read error occurs, theerror indicator(ferror) is set and a null pointer is also returned (but the contents pointed bystrmay have changed).
簡(jiǎn)單點(diǎn)說:遇到錯(cuò)誤和文件結(jié)尾都會(huì)返回NULL,但會(huì)設(shè)置不同的指示器(feof,ferror)(后面會(huì)說)
3.格式化輸入輸出函數(shù)
fprintf--- 格式化輸出函數(shù) 聲明
int fprintf ( FILE * stream, const char * format, ... );
fscanf--- 格式化輸入函數(shù)聲明
int fscanf ( FILE * stream, const char * format, ... );
別看他們倆長(zhǎng)得花里胡哨的,但是使用卻和我們的printf,scanf大致相同,只是多出了一個(gè)流的填寫
我們來看看 printf 和 scanf的聲明:
int scanf ( const char * format, ... );int printf ( const char * format, ... );
所以我們來看一個(gè)示例:
示例 1:
struct Stu { char name[20]; int age; float score; }; int main() { struct Stu s = {"zhangsan", 20, 66.5f}; FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { printf("%s\n", strerror(errno)); return 1; } //格式化的寫入 fprintf(pf,"%s %d %f", s.name, s.age, s.score); //printf("%s %d %f", s.name, s.age, s.score);//對(duì)比一下只是差了一個(gè) 流 的指定 //關(guān)閉文件 fclose(pf); pf = NULL; return 0; }
注意:
讀取錯(cuò)誤或結(jié)束時(shí),fscanf 的返回值也是EOF,判斷同 fgetc
這里其實(shí)還有一組與它倆相似的函數(shù) ---sprintf以及sscanf (點(diǎn)擊函數(shù)名看文檔)
它倆是干什么的呢,一個(gè)是把結(jié)構(gòu)化的數(shù)據(jù)轉(zhuǎn)換為字符串,一個(gè)是把字符串轉(zhuǎn)化為結(jié)構(gòu)化的數(shù)據(jù)
同樣,我們來看看聲明:
[code]int sprintf ( char * str, const char * format, ... );
char * str --- 我們要把格式化生成的字符串所存放的地址
int sscanf ( const char * s, const char * format, ...);
const char * s --- 我們所要讀取的字符串
示例:
struct Stu { char name[20]; int age; float score; }; int main() { struct Stu s = {"zhangsan", 20, 66.5f}; char buf[200] = { 0 }; //sprintf可以把結(jié)構(gòu)化的數(shù)據(jù)轉(zhuǎn)換為一個(gè)字符串 sprintf(buf, "%s %d %f", s.name, s.age, s.score); printf("按照字符串的形式:%s\n", buf); struct Stu tmp = { 0 }; //sscanf可以把一個(gè)字符串轉(zhuǎn)換為一個(gè)結(jié)構(gòu)化的數(shù)據(jù) sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score)); printf("按照格式化的形式:%s %d %f\n", tmp.name, tmp.age, tmp.score); return 0; }
4.二進(jìn)制輸入輸出函數(shù)
fwrite--- 二進(jìn)制寫文檔
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
這個(gè)函數(shù)解釋一下就是:將來自 ptr 指向的數(shù)據(jù),一次寫size個(gè)字節(jié),共寫 count 次,輸出到 stream 指定的流中
fread--- 二進(jìn)制讀文檔
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
這個(gè)函數(shù)解釋一下就是:將 stream 指定的流中 讀 count 次,一次讀 size 個(gè)字節(jié),存到 ptr 所指向的內(nèi)容中
示例:
// data.txt 內(nèi)容 zhangsan 20 66.500000 int main() { struct Stu s = {0}; FILE* pf = fopen("data.txt", "rb");//binary --- 二進(jìn)制 if (pf == NULL) // rb --- 二進(jìn)制讀 { printf("%s\n", strerror(errno)); return 1; } //讀文件-二進(jìn)制 fread(&s, sizeof(struct Stu), 1, pf); printf("%s %d %f\n", s.name, s.age, s.score); fclose(pf); pf = NULL; return 0; }
注:
若讀取時(shí)發(fā)現(xiàn)讀取的內(nèi)容的個(gè)數(shù)比指定的最大個(gè)數(shù)小時(shí),就結(jié)束,然后判斷是讀到文件末尾,還是讀取失敗
示例 2:
int main() { int a = 10000; FILE*pf = fopen("bin.dat", "wb");//二進(jìn)制寫 if (pf == NULL) { return 1; } fwrite(&a, sizeof(int), 1, pf); fclose(pf); pf = NULL; return 0; }
3.文件的隨機(jī)讀寫
1.seek ---根據(jù)文件指針的位置和偏移量來定位文件指針。
int fseek ( FILE * stream, long int offset, int origin );
FILE * stream --- 流
long int offset --- 偏移量
int origin --- 從哪里開始,有三個(gè)選擇
1.SEEK_SET --- 從文件頭開始
2.SEEK_CUR --- 從當(dāng)前位置開始
3.SEEk_END --- 從文件末尾開始
示例:
//此時(shí)文件內(nèi)容為:123456789 int main() { FILE* fp = fopen("data.txt", "r"); if (fp == NULL) { perror("\n"); exit(1); } char a = fgetc(fp); printf("%c ", a);//此時(shí)結(jié)果為 1,現(xiàn)在指針指向 2 a = fgetc(fp);//此時(shí)讀取2,指針指向 3 printf("%c ", a); fseek(fp, -1, SEEK_END);//將文件指針置于文章末尾 a = fgetc(fp);//此時(shí)讀取9,指針再次指向末尾 printf("%c ", a); fseek(fp, 1, SEEK_SET);//將文件指針置于文章頭 a = fgetc(fp);//此時(shí)讀取1,指針再次指向2 printf("%c ", a); fclose(fp); fp = NULL; return 0; }
2.ftell ---返回文件指針相對(duì)于起始位置的偏移量
long int ftell ( FILE * stream );
3.rewind ---讓文件指針的位置回到文件的起始位置
void rewind ( FILE * stream );
示例:
int main() { FILE*pf = fopen("data.txt", "r"); if (pf == NULL) { return 1; } //讀取 int ch = fgetc(pf); printf("%c\n", ch); ch = fgetc(pf); printf("%c\n", ch); //定位文件指針到文件的起始位置 //fseek(pf, -2,SEEK_CUR); //fseek(pf, 0, SEEK_SET); //printf("%d\n", ftell(pf)); rewind(pf); ch = fgetc(pf);//要在這里讀取'a' printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
4.文件緩存區(qū)的刷新
我們?cè)谏衔奶岬轿募彌_區(qū)的概念:
緩沖文件系統(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ū)),然后再?gòu)木彌_區(qū)逐個(gè)地將數(shù)據(jù)送到程序數(shù)據(jù)區(qū)(程序變量等)。
緩沖區(qū)的大小根據(jù)C編譯系統(tǒng)決定的。
所以,當(dāng)我們?cè)诔绦蛑忻钣?jì)算機(jī)往文件中寫一些東西的時(shí)候,如果我們想在輸出語句已結(jié)束,文件就有內(nèi)容(即需要寫的內(nèi)容從文件緩沖區(qū)寫到了文件中),
此時(shí),我們不妨fflush一下
fflush --- 刷新文件緩存區(qū)
int fflush ( FILE * stream );
參數(shù)就是我們所定義的文件指針。
示例:
#include <stdio.h> #include <windows.h> //VS2019 WIN10環(huán)境測(cè)試 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ū)時(shí),才將輸出緩沖區(qū)的數(shù)據(jù)寫到文件(磁盤) //注:fflush 在一些編譯器上并不能使用 printf("再睡眠10秒-此時(shí),再次打開test.txt文件,文件有內(nèi)容了\n"); Sleep(10000); fclose(pf); //注:fclose在關(guān)閉文件的時(shí)候,也會(huì)刷新緩沖區(qū) pf = NULL; return 0; }
三.一個(gè)易被誤用的點(diǎn)
feof的錯(cuò)誤使用
在剛才的講解中,我們已經(jīng)都說過了各輸入函數(shù)遇到錯(cuò)誤時(shí)的返回值,所以我們?cè)趯懳募h(huán)讀取的循環(huán)條件時(shí),一定要注意各函數(shù)的返回值的區(qū)別 !
在不滿足循環(huán)條件后 判斷是發(fā)生錯(cuò)誤跳出,還是讀到文本末尾結(jié)束(這就是前面所說到的指示器 feof --- 文本結(jié)束, ferror --- 遇到錯(cuò)誤)
如圖:
示例:
int main() { FILE*pf = fopen("data.txt", "r"); if (pf == NULL) { return 1; } //讀取 int ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c ", ch); } //找結(jié)束的原因 if (ferror(pf)) { printf("讀取是發(fā)生錯(cuò)誤,失敗,而結(jié)束\n"); } else if (feof(pf)) { printf("遇到文件末尾,而結(jié)束的\n"); } fclose(pf); pf = NULL; return 0; }
所以,我們?cè)谌粘J褂玫臅r(shí)候要注意這個(gè)點(diǎn)!
總結(jié)
到此這篇關(guān)于C語言文件操作入門詳解教程的文章就介紹到這了,更多相關(guān)C語言文件操作內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Matlab實(shí)現(xiàn)野狗優(yōu)化算法的示例代碼
野狗優(yōu)化算法(Dingo?Optimization?Algorithm,?DOA)模仿澳大利亞野狗的社交行為。DOA算法的靈感來源于野狗的狩獵策略,即迫害攻擊、分組策略和食腐行為。本文將通過Matlab實(shí)現(xiàn)這一算法,感興趣的可以了解一下2022-04-04C++使用string的大數(shù)取模運(yùn)算(5)
這篇文章主要為大家詳細(xì)介紹了C++使用string的大數(shù)取模運(yùn)算,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09C++?二叉樹的實(shí)現(xiàn)超詳細(xì)解析
二叉樹可以簡(jiǎn)單理解為對(duì)于一個(gè)節(jié)點(diǎn)來說,最多擁有一個(gè)上級(jí)節(jié)點(diǎn),同時(shí)最多具備左右兩個(gè)下級(jí)節(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)。本文將詳細(xì)介紹一下C++中二叉樹的實(shí)現(xiàn)和遍歷,需要的可以參考一下2022-03-03C++標(biāo)準(zhǔn)庫(kù)bitset類型的簡(jiǎn)單使用方法介紹
這篇文章主要介紹了C++標(biāo)準(zhǔn)庫(kù)bitset類型的簡(jiǎn)單使用方法,需要的朋友可以參考下2017-07-07C++實(shí)現(xiàn)冒泡排序(BubbleSort)
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)冒泡排序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04C++ map 根據(jù)value找key的實(shí)現(xiàn)
今天小編就為大家分享一篇C++ map 根據(jù)value找key的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-12-12C語言 makefile學(xué)習(xí)及實(shí)現(xiàn)實(shí)例
這篇文章主要介紹了C語言 makefile學(xué)習(xí)及實(shí)現(xiàn)實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03