目錄
什么是文件
?文件分類
程序文件
數(shù)據(jù)文件
文件的使用
?文件指針
文件指針的使用
?文件的打開(kāi)和關(guān)閉
文件的使用方式
?文件的順序讀寫(xiě)
1.寫(xiě)入一個(gè)字符
2.讀取一個(gè)字符
3.連續(xù)每次讀取一個(gè)字符
4.覆蓋并寫(xiě)入一行數(shù)據(jù)
5.讀取指定長(zhǎng)度的數(shù)據(jù)
6.將結(jié)構(gòu)體信息寫(xiě)入文件中
7.讀取文件信息到結(jié)構(gòu)體變量中
8.二進(jìn)制寫(xiě)入文件
9.讀取二進(jìn)制文件信息
10.sscanf()函數(shù)、sprintf()函數(shù)
文件的隨機(jī)讀寫(xiě)
?fseek()函數(shù)
?ftell函數(shù)()
??rewind()函數(shù)
二進(jìn)制文件和文本文件
文件讀取結(jié)束判定
?feof()函數(shù)
文本文件的判斷
二進(jìn)制文件的判斷
📌————本章重點(diǎn)————📌
🔗文件指針
🔗文件的順序讀寫(xiě)
🔗文件的隨機(jī)讀寫(xiě)
🔗文件讀取結(jié)束判定
?————————————?
與普通文件載體不同,文件是以硬盤(pán)為載體存儲(chǔ)在計(jì)算機(jī)上的信息集合,文件可以是文本文檔、圖片、程序等等。文件通常具有點(diǎn)+三個(gè)字母的文件擴(kuò)展名,用于指示文件類型(例如,圖片文件常常以KPEG格式保存并且文件擴(kuò)展名為.jpg)。
? 將數(shù)據(jù)放入文件中,相比代碼程序中堆棧上的數(shù)據(jù),其優(yōu)點(diǎn)在于可以隨時(shí)做到需要時(shí)添加、舍棄時(shí)刪除,數(shù)據(jù)可以持久化。
文件分類:? 文件一般講兩種:程序文件和數(shù)據(jù)文件;
程序文件:包括源程序文件(后綴為.c),目標(biāo)文件(windows環(huán)境后綴為.obj),可執(zhí)行程序(windows環(huán)境后綴為.exe)。
數(shù)據(jù)文件:? 包括程序運(yùn)行時(shí)所讀寫(xiě)的數(shù)據(jù)。本篇所涉及的就是數(shù)據(jù)文件。
文件的操作一般分三步:1.打開(kāi)文件;2.讀/寫(xiě);3.關(guān)閉文件;
? 想要對(duì)文件進(jìn)行操作,“文件指針”就是一個(gè)關(guān)鍵橋梁(亦名:文件類型指針);????????????????
文件指針的使用:底層原理:每個(gè)被使用的文件,都在內(nèi)存中開(kāi)辟了一個(gè)相應(yīng)的文件信息區(qū),用來(lái)存放文件的相關(guān)信息(如:文件名、文件狀態(tài)、文件位置等),這些信息被保存到一個(gè)結(jié)構(gòu)體中,系統(tǒng)為其聲明為FILE,每當(dāng)打開(kāi)一個(gè)文件的時(shí)候,系統(tǒng)就會(huì)根據(jù)情況自動(dòng)創(chuàng)建一個(gè)FILE結(jié)構(gòu)的變量,并且通過(guò)FILE*的指針來(lái)維護(hù)這個(gè)結(jié)構(gòu)。
FILE* pf;
定義一個(gè)文件指針變量pf,它可以指向某個(gè)文件的文件信息區(qū),通過(guò)其即可訪問(wèn)到該文件。
在打開(kāi)文件的同時(shí),都會(huì)返回一個(gè)FILE*的指針變量指向該文件,也相當(dāng)于建立了指
針和文件的關(guān)系。
文件的使用方式:
- fopen() —— 打開(kāi)文件;
- FILE * fopen ( const char * filename, const char * mode );
- fclose() —— 關(guān)閉文件;
- int fclose ( FILE * stream );
按常用序:
使用方式 | 作用? | 如果文件不存在 |
"r"(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)已經(jīng)存在的文本文件 | 出錯(cuò)? ? ? ? ? ? ? ?? |
"w"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本文件 | 建立一個(gè)新的文件 |
"a"(追加) | 向文本文件添加數(shù)據(jù) | 建立一個(gè)新的文件 |
"rb"(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
"wb"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 建立一個(gè)新的文件 |
"ab"(追加) | 向一個(gè)二進(jìn)制文件尾添加數(shù)據(jù) | 出錯(cuò) |
"r+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)文本文件 | 出錯(cuò) |
"w+"(讀寫(xiě)) | 為了讀和寫(xiě),建立一個(gè)新的文本文件 | 建立一個(gè)新的文件 |
"a+"(讀寫(xiě)) | 打開(kāi)一個(gè)文本文件,在文件尾進(jìn)行讀寫(xiě) | 建立一個(gè)文件 |
"rb+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
"wb+"(讀寫(xiě)) | 為了讀和寫(xiě),建立一個(gè)新的二進(jìn)制文件 | 建立一個(gè)新的文件 |
"ab+"(讀寫(xiě)) | 打開(kāi)一個(gè)二進(jìn)制文件,在文件尾進(jìn)行讀寫(xiě) | 建立一個(gè)新的文件 |
函數(shù)名 | 功能 | 適用性 |
fgetc() | 字符輸入函數(shù) | 所有輸入流 |
fputc() | 字符輸出函數(shù) | 所有輸出流 |
fgets() | 文本行輸入函數(shù) | 所有輸入流 |
fputs() | 文本行輸出函數(shù) | 所有輸出流 |
fscanf() | 格式化輸入函數(shù) | 所有輸入流 |
fprintf() | 格式化輸出函數(shù) | 所有輸出流 |
fread() | 二進(jìn)制輸入 | 文件 |
fwrite() | 二進(jìn)制輸出 | 文件 |
以上結(jié)合起來(lái)實(shí)例:
#include#include#includeint main()
{
FILE* pf= fopen("test.txt", "w+");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return;
}
//輸入一個(gè)字符
fputc('a', pf);
//用完關(guān)閉文件
fclose(pf);
pf = NULL;
return 0;
}
如圖示:在源文件所在目錄下,原本沒(méi)有test.txt文件,是w+創(chuàng)建了這個(gè)新的文件,并寫(xiě)入一個(gè)字符a?
//寫(xiě)文件
fputc('a', pf);
2.讀取一個(gè)字符://讀取一個(gè)字符
int ch = fgetc(pf);
if (ch != EOF)
{
printf("%c\n", ch);
}
3.連續(xù)每次讀取一個(gè)字符://文件中有abcdefg
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
4.覆蓋并寫(xiě)入一行數(shù)據(jù):fputs("hello world", pf);
注意:這里fputs函數(shù)雖然是整行寫(xiě)入,但會(huì)覆蓋掉原始數(shù)據(jù)、
//定一一個(gè)數(shù)組
char arr[10] = { 0 };
fgets(arr, 5, pf); //將所讀取的數(shù)據(jù)放入arr中
printf("%s\n", arr);
這里的結(jié)構(gòu)體信息就是格式化的,那么就需要fprintf()函數(shù)了
#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "w");
if (pf != NULL)
{
Peo p = { "zhangsan", 18 };
fprintf(pf, "%s %d\n", p.name, p.age);
fclose(pf);
pf = NULL;
}
return 0;
}
#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf != NULL)
{
Peo p = { 0 };
fscanf(pf, "%s %d", p.name, &p.age);
printf("%s %d", p.name, p.age);
fclose(pf);
pf = NULL;
}
return 0;
}
- size_t fwrite( const void *buffer, size_tsize, size_tcount, FILE *stream);
#include#include#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "wb+");
if (pf != NULL)
{
Peo p = { "lisi", 19};
fwrite(&p, sizeof(Peo), 1, pf);
fclose(pf);
pf = NULL;
}
return 0;
}
size_t fread( void *buffer, size_tsize, size_tcount, FILE *stream);
#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
FILE* pf = fopen("test.txt", "rb+");
if (pf != NULL)
{
Peo p = { 0 };
fread(&p, sizeof(Peo), 1, pf);
printf("%s %d\n", p.name, p.age);
fclose(pf);
pf = NULL;
}
return 0;
}
這兩個(gè)函數(shù)雖然和文件操作關(guān)系不大,但是容易與文件操作函數(shù)混淆;
- int sscanf( const char *buffer, const char *format[,argument] ... );
- 將一個(gè)字符串轉(zhuǎn)化為格式化數(shù)據(jù);
#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
//定義一個(gè)字符串
char buffer[] = { "zhansan 19" };
//定義一個(gè)結(jié)構(gòu)但不賦值
Peo p = { 0 };
sscanf(buffer, "%s %d", p.name, &p.age);
return 0;
}
int sprintf( char *buffer, const char *format[,argument] ... );
將一個(gè)格式化數(shù)據(jù)轉(zhuǎn)化為字符串;
#includetypedef struct S
{
char name[10];
int age;
}Peo;
int main()
{
//定義一個(gè)結(jié)構(gòu)
Peo p = { "zhangsan",19};
//定義一個(gè)字符串
char buffer[50] = { 0 };
sprintf(buffer, "%s %d\n", p.name, p.age);
return 0;
}
所謂的隨機(jī)讀寫(xiě),其實(shí)就是指定我們想要讀寫(xiě)的位置。
fseek()函數(shù):
- 該函數(shù)可以從定位位置的偏移量處開(kāi)始讀寫(xiě);
- int fseek( FILE *stream, long offset, int origin );
文件流? ? ? ? ??偏移量? ? 起始位置?- 返回值:
- 如果成功,fseek返回0;
- 否則,它返回一個(gè)非零值;
- 在無(wú)法查找的設(shè)備上,返回值未定義;? ? ? ??
三種定位指針:
使用實(shí)例:
#include#include#includeint main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return;
}
//開(kāi)始多次讀取
//定位指針:比如要讀取從頭開(kāi)始向后偏移 2 個(gè)單位的一個(gè)字符
fseek(pf, 2, SEEK_SET);
int ch = fgetc(pf);
printf("%c\n", ch);
//第二次讀?。阂玫疆?dāng)前文件指針?biāo)幬恢孟蚝笃?個(gè)單位的字符
fseek(pf, 5, SEEK_CUR);
ch = fgetc(pf);
printf("%c\n", ch);
//第三次讀取:要拿到文件流末尾向前偏移8個(gè)單位的一個(gè)字符
fseek(pf, -8, SEEK_END);
ch = fgetc(pf);
printf("%c\n", ch);
fclose(pf);
pf = NULL;
return 0;
}
ftell函數(shù)():特別說(shuō)明:
在每使用完一次fseek函數(shù)后,文件指針會(huì)自動(dòng)向后移動(dòng)一位:
- 該函數(shù)可以返回文件指針相對(duì)于起始位置的偏移量;
- long int ftell ( FILE * stream );
使用實(shí)例:
我們直接在上一段代碼的基礎(chǔ)上加上ftell()函數(shù)即可直觀得到每次文件指針?biāo)幍奈恢茫?/p>
- 讓文件指針回到文件初始位置;
- void rewind ( FILE * stream );
使用實(shí)例:
我們知道數(shù)據(jù)在內(nèi)存中是以二進(jìn)制形式存儲(chǔ)的,對(duì)于文件而言:如果不加轉(zhuǎn)換直接輸出到外存就是二進(jìn)制文件;如果要在外存上以ASCII碼形式存儲(chǔ),就需要提前轉(zhuǎn)換最后以ASCII碼值形式存儲(chǔ)的文件就是文本文件。
對(duì)于字符,一律使用ASCII碼形式存儲(chǔ),但對(duì)于數(shù)值型數(shù)據(jù),即可以使用ASCII碼存儲(chǔ)也可以使用二進(jìn)制形式存儲(chǔ)。
舉例:
數(shù)字10000的兩種存儲(chǔ)形式:
二進(jìn)制文件:
文本文件:
首先將10000分成'1','0','0','0','0',?這五個(gè)字符,用每個(gè)字符對(duì)應(yīng)的ASCII碼值進(jìn)行轉(zhuǎn)換:
由此可見(jiàn):對(duì)于10000在數(shù),如果以二進(jìn)制形式存儲(chǔ)占用4個(gè)字節(jié),如果以ASCII碼存儲(chǔ)占用5個(gè)字節(jié)。試想:那對(duì)于數(shù)字1呢?
顯而易見(jiàn),二進(jìn)制文件存儲(chǔ)和文本文件存儲(chǔ)對(duì)不同范圍的數(shù)字可以做到節(jié)省空間。
對(duì)二進(jìn)制文件深入理解:
#includeint main()
{
FILE* pf = fopen("test.txt", "wb");
int a = 10000;
if (pf != NULL)
{
fwrite(&a, 4, 1, pf);
fclose(pf);
pf = NULL;
}
return 0;
}
對(duì)于上面這段代碼,我們知道是將數(shù)值10000放入了test.txt文件中,但我們無(wú)法直接看到它在文件中的真實(shí)值,于是使用vs的二進(jìn)制編輯器即可查看:
該函數(shù)被許多人錯(cuò)誤用來(lái)判斷文件是否讀取結(jié)束,其實(shí)它的作用是判斷文件讀取結(jié)束的原因;
文本文件的判斷:文件讀取結(jié)束有兩種情況:1.讀取過(guò)程中出現(xiàn)異常; 2.讀取到文件末尾;
要找出文件讀取是哪個(gè)原因,就分為以下情況:
文本文件:
- 如果用 fgetc() 讀取,要判斷 feof() 的返回值是否為EOF;
- 如果用 fgets() 讀取,要判斷 feof() 的返回值是否為NULL(0);
二進(jìn)制文件:
都是使用 fread() 讀取,要判斷其返回值與指定讀取個(gè)數(shù)的大小,如果小于實(shí)際要讀的個(gè)數(shù),就說(shuō)明發(fā)生讀取異常,如果等于實(shí)際要讀的個(gè)數(shù),就說(shuō)明是因讀取成功而結(jié)束;
對(duì)于讀取異常的判斷,我們考慮判斷 ferror() 函數(shù)的返回值:
- 若ferrror()為真——異常讀取而結(jié)束;
- 若feof()為真——正常讀取到尾而結(jié)束;
#include#include#includeint main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen is failed !");
return;
}
int c = 0;
//由于要檢查EOF——EOF本質(zhì)是0——所以是int
while (c = fgetc(pf) != EOF)
{
putchar(c);
}
//直到while不執(zhí)行了—讀取結(jié)束了—判斷是什么原因結(jié)束的
if (ferror(pf))
{
printf("讀取中出現(xiàn)錯(cuò)誤\n");
}
else if (feof(pf))
{
printf("讀取到文件尾\n");
}
fclose(pf);
pf = NULL;
return 0;
}
二進(jìn)制文件的判斷:#include#include#includeint main()
{
FILE* pf = fopen("test.txt", "rb");
int arr[5] = { 0 };
if (pf == NULL)
{
return;
}
size_t num = fread(arr, sizeof(int), 5, pf);
if (num == 5)
{
//說(shuō)明全部讀取成功
printf("Array read successfully\n");
}
else
{
//說(shuō)明讀取不夠指定長(zhǎng)度—判斷是什么原因
if (ferror(pf))
{
printf("讀取中出現(xiàn)錯(cuò)誤\n");
}
else if (feof(pf))
{
printf("讀取到文件尾\n");
}
}
fclose(pf);
pf = NULL;
return 0;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧
當(dāng)前名稱:C語(yǔ)言文件操作(超詳細(xì)版)-創(chuàng)新互聯(lián)
鏈接地址:http://vcdvsql.cn/article16/hddgg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供移動(dòng)網(wǎng)站建設(shè)、網(wǎng)站導(dǎo)航、電子商務(wù)、小程序開(kāi)發(fā)、手機(jī)網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容