国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
C語言之文件操作

https://m.toutiaocdn.com/i6847739122979701260/?app=news_article&timestamp=1594400967&use_new_style=1&req_id=20200711010927010129040078043AEF9D&group_id=6847739122979701260 



前些時(shí)候,我們學(xué)習(xí)的C語言程序都是由輸入輸出和算法組成的控制臺程序。我們在終端上來輸入我們提供的數(shù)據(jù),然后程序也會通過終端來告訴我們最終運(yùn)行的結(jié)果。

但是,可能有的同學(xué)已經(jīng)觀察到了,我們?nèi)粘J褂玫膭e人開發(fā)的程序,大多數(shù)都是通過文件來提供數(shù)據(jù)的。比如一個(gè)Excel的報(bào)表,程序可以直接來分析里面的數(shù)據(jù)。再比如,一個(gè)TXT格式的電子書,程序可以直接分析有多少字、多少個(gè)章節(jié),甚至還可以生成出一個(gè)目錄來。

擁有這樣能力的程序,是不是感覺功能強(qiáng)大了許多?這就要用到我們今天要講到的內(nèi)容——「文件操作」。

關(guān)于文件

在我們比較熟悉的Windows系統(tǒng)下,文件類型的區(qū)分是用「擴(kuò)展名」來進(jìn)行的。但其實(shí)擴(kuò)展名并不是指「文件格式」,它只是一個(gè)「門牌號」而已。至于它到底對不對,那系統(tǒng)就不知道了??赡苡泻芏嗟男率?,在遇到格式的問題的時(shí)候,會認(rèn)為直接更改擴(kuò)展名,就能實(shí)現(xiàn)格式轉(zhuǎn)換。不瞞你們說,我小時(shí)候也有過這種想法。但是后來發(fā)現(xiàn),不行。舉個(gè)例子,現(xiàn)在有一個(gè) MP3 的文件,要轉(zhuǎn)成 AAC。這兩個(gè)文件從編碼上來講,就是不一樣的。MP3 只能用 MP3 的方式去讀取,AAC 只能用 AAC 的方式去讀取。如果你把擴(kuò)展名直接改成 AAC,那么系統(tǒng)就被你騙了,就會用 AAC 的方式去讀取實(shí)際還是 MP3 的文件,當(dāng)然是不行了。

不同的擴(kuò)展名,就對應(yīng)了不同的讀取方式。「EXE」 就代表 Windows 系統(tǒng)下的可執(zhí)行二進(jìn)制文件,「TXT」是純文本文件,等等。

在 Linux 和 Unix 操作系統(tǒng)下,文件的定義就寬泛多了。不光軟件,硬件也可以叫文件。也就是說,硬件實(shí)際上也是當(dāng)做文件的方式來處理的。

在C語言中,文件一般分為兩種,一種是二進(jìn)制文件,就是我們編譯出來的那個(gè)東西,我們是看不懂的;另一種是文本文件,也就是我們常說的源代碼。

打開和關(guān)閉文件

我們要對一個(gè)文件進(jìn)行操作,首先我們需要把文件打開,然后才能讀或者寫。對文件操作完成后,我們還要將文件關(guān)閉。

C語言中的打開文件使用fopen函數(shù),通式如下:

fopen('文件路徑', '模式')

如果打開文件成功,則會返回一個(gè)FILE結(jié)構(gòu)的指針,通過這個(gè)指針,我們就可以對這個(gè)文件進(jìn)行操作;如果打開文件失敗,則會返回NULL。

下面是所有的模式:

前面幾個(gè)都好理解,只是最后一個(gè),為啥要區(qū)分一個(gè)二進(jìn)制出來呢?

不加「b」的情況下,就是以文本的形式來打開。因?yàn)樵诓煌牟僮飨到y(tǒng)中,換行符是不同的。Unix系統(tǒng)用\n,MacOS用\r,而Windows用的是\r\n,那么在文本模式下打開,C語言會根據(jù)系統(tǒng)環(huán)境的不同,來轉(zhuǎn)化換行符。而在二進(jìn)制的模式下,就不會進(jìn)行任何的轉(zhuǎn)換。

當(dāng)你對文件操作完畢后,一定要記得把文件用fclose()函數(shù)來關(guān)閉。其實(shí)我們在打開文件后的所有操作,實(shí)際上都被記錄到了緩存里,只有執(zhí)行了關(guān)閉后,我們的更改才會生效。如果關(guān)閉成功,則函數(shù)會返回0;失敗的話,就會返回EOF。關(guān)閉成功后,我們創(chuàng)建的文件指針就會失效。

//Example 01//學(xué)習(xí)交流群:782648055#include <stdio.h>#include <stdlib.h>int main(void){ FILE* f; int chr; if ((f = fopen('file1.txt', 'r')) == NULL) { printf('打開失敗!\n'); exit(EXIT_FAILURE); } while ((chr = getc(f)) != EOF) { putchar(chr); } fclose(f); return 0;}
//file1.txt中的內(nèi)容C programming makes me happy!
//Consequence 01C programming makes me happy!

順序讀寫文件

打開了文件之后,就可以進(jìn)行我們的操作了。

讀寫單個(gè)字符

讀取單個(gè)字符,我們可以用fgetc和getc這兩個(gè)來實(shí)現(xiàn)。它們的作用,就是讀取一個(gè)字符,然后將光標(biāo)移動到下一個(gè)位置。

#include <stdio.h>...int fgetc(FILE* stream);int getc(FILE* stream);

函數(shù)的參數(shù),是一個(gè)FILE結(jié)構(gòu)體的指針,也就是一個(gè)準(zhǔn)確讀取的文件流。讀取成功就會將讀取到的unsigned char內(nèi)容轉(zhuǎn)化為int并返回;文件結(jié)束或者讀取失敗就返回EOF。

這倆函數(shù)不同的地方就在于,fgetc是函數(shù)實(shí)現(xiàn),而getc是用宏實(shí)現(xiàn)。宏會產(chǎn)生大量的代碼量,但是沒有函數(shù)調(diào)用堆棧的步驟,所以速度會快很多。但是宏的展開可能會多次調(diào)用參數(shù),因此如果參數(shù)中含有自增、自減這種副作用的的方法,就只能用函數(shù)實(shí)現(xiàn)的fgetc了。

寫入單個(gè)字符,我們可以用fputc和putc,帶有f的,就是函數(shù),另一個(gè)就是宏的實(shí)現(xiàn)的了。

#include <stdio.h>...int fputc(int c, FILE* stream);int putc(int c, FILE* stream);

第一個(gè)參數(shù)是你要寫入的字符,第二個(gè)是你要寫入的文件流。

讀寫整個(gè)字符串

這里就要用到fgets和fputs兩個(gè)函數(shù)了。

#include <stdio.h>...charfgets(char* s, int size, FILE* stream);int fputs(const chat* s, FILE* stream);

其中,fgets有三個(gè)參數(shù),第一個(gè)是一個(gè)字符型指針,用來存放讀取的數(shù)據(jù);第二個(gè)用來指定讀取的長度(包含'\0');第三個(gè)是用于指定讀取的文件流。

函數(shù)調(diào)用成功后,會返回第一個(gè)參數(shù)所指向的地址。如果讀取到EOF則eof指示器被設(shè)置。若一開始就讀取到EOF,第一個(gè)參數(shù)的內(nèi)容不變,返回NULL。若讀取發(fā)生錯(cuò)誤,則error指示器被設(shè)置,函數(shù)返回NULL,第一個(gè)參數(shù)內(nèi)容可能會被改變。

fputs第一個(gè)參數(shù)用于存放待寫入的數(shù)據(jù),第二個(gè)是指定待寫入的文件流。函數(shù)調(diào)用成功,返回一個(gè)非 0 值,失敗則返回EOF。

格式化讀寫文件

在文件里,我們就不能用我們熟悉的scanf和printf了。但是C語言也提供一組類似的函數(shù):fscanf和fprintf。

用法上,第一個(gè)參數(shù)用于指定文件流,后面的就是照搬的scanf和printf中的參數(shù)。

//Example 02#include <stdio.h>#include <stdlib.h>#include <time.h>int main(void){    FILE* fp;    struct  tmp;    time_t t;        time(&t);    p = localtime(&t);    //寫入日期到文件    if ((fp = fopen('date.txt''w')) == NULL)    {        printf('打開文件失?。n');        exit(EXIT_FAILURE);    }    fprintf(fp, '%d-%d-%d'1900 + p -> tm_year, 1 + p -> tm_mon, p -> tm_mday);    fclose(fp);    //讀取文件日期,輸出到終端    int year, month, day;    if ((fp = fopen('date.txt''r')) == NULL)    {        printf('打開文件失?。n');        exit(EXIT_FAILURE);    }    fscanf(fp, '%d-%d-%d', &year, &month, &day);    printf('%d-%d-%d\n', year, month, day);    fclose(fp);    return 0;}
//date.txt中的內(nèi)容2020-6-15
//Consequence 022020-6-15

二進(jìn)制讀寫

我們用fopen函數(shù)可以用二進(jìn)制的方式來打開一個(gè)文件,但實(shí)際上我們要用二進(jìn)制的方式來讀寫,還得用相應(yīng)的函數(shù)才行。

C語言提供了fread和fwrite兩個(gè)函數(shù)來實(shí)現(xiàn)二進(jìn)制的讀取和寫入。

#include <stdio.h>...size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);

首先來看fread。這個(gè)函數(shù)有四個(gè)參數(shù)。第一個(gè)指向存放數(shù)據(jù)的地址,第二個(gè)指定讀取的每個(gè)元素的尺寸,第三個(gè)指定準(zhǔn)備讀取的元素個(gè)數(shù),最后一個(gè)指向待讀取的文件流。

函數(shù)調(diào)用成功,會返回讀取到的元素個(gè)數(shù),如果實(shí)際讀取的比第三個(gè)參數(shù)小,那么可能會一直讀取到文件末尾或者發(fā)生錯(cuò)誤,這種情況就要通過foef和ferror來進(jìn)一步判斷。

然后是fwrite,也是有四個(gè)參數(shù)。第一個(gè)是指向存放數(shù)據(jù)的地址,第二個(gè)是指定待寫入的每個(gè)元素的尺寸,第三個(gè)是指定待寫入的元素的個(gè)數(shù),最后一個(gè)是指向待寫入的文件流。

隨機(jī)讀寫文件

剛剛我們介紹的,都是從文件頭開始讀寫。但是我們實(shí)際生產(chǎn)生活中,很多時(shí)候我們是需要任意修改的。比如改一個(gè)文檔,很有可能是中間的什么地方錯(cuò)了,或者是表達(dá)有不妥。那么這個(gè)時(shí)候如果你還要從頭開始去檢索,那樣效率就太低了。

于是,C語言也為我們提供了這個(gè)功能,就是隨機(jī)讀寫。

首先,我們要了解光標(biāo)的位置,才能夠更好地運(yùn)用這個(gè)功能。C語言為我們提供了ftell函數(shù),它可以告訴我們現(xiàn)在的光標(biāo)位置。

#include <stdio.h>...long ftell(FILE* stream);

如果將一個(gè)文件看成一個(gè)數(shù)組,那么這個(gè)函數(shù)返回的就是這個(gè)數(shù)組的下標(biāo)。

//Example 01#include <stdio.h>#include <stdlib.h>int main(void){    FILE* fp;    if ((fp = fopen('data.txt''w')) == NULL)    {        printf('文件打開失??!\n');        exit(EXIT_FAILURE);    }    printf('%ld\n', ftell(fp));    fputc('T', fp);    printf('%ld\n', ftell(fp));    fputs('echZone\n', fp);    printf('%ld\n', ftell(fp));    fclose(fp);        return 0;}
//data.txt中的內(nèi)容TechZone
//Consequence 010110

如果你想將光標(biāo)快速移動到文件頭,可以用rewind函數(shù)來實(shí)現(xiàn)。

...rewind(fp);fputs('Hello', fp);fclose(fp);...
//data.txt中的內(nèi)容Helloone

可以看到,它會覆蓋我們前面的數(shù)據(jù)。

有的同學(xué)可能會說了,你這不還是沒解決問題嗎?

好的,那就來解決下問題吧。C語言給我們提供了一個(gè)函數(shù)fseek,這個(gè)函數(shù)可以直接把光標(biāo)跳轉(zhuǎn)到我們想要的位置。

#include <stdio.h>...int fseek(FILE* stream, long int offset, int whence);

第一個(gè)參數(shù)是指的我們要讀取的文件流,第二個(gè)是偏移量(往后走是正數(shù),往前走是負(fù)數(shù)),第三個(gè)是指的開始偏移的位置。

值描述SEEK_SET文件開頭SEEK_CUR當(dāng)前位置SEEK_END文件末尾

如果我要定位到第一百個(gè)字符的位置,那么:

fseek(fp, 100, SEEK_SET)

倒數(shù)第 10 個(gè)就要這樣:

fseek(fp, -10, SEEK_END)

標(biāo)準(zhǔn)流

標(biāo)準(zhǔn)輸入,標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤輸出

一般C語言程序在執(zhí)行的時(shí)候,都會有 3 個(gè)面向終端的文件流,分別是「標(biāo)準(zhǔn)輸入」,「標(biāo)準(zhǔn)輸出」「標(biāo)準(zhǔn)錯(cuò)誤輸出」。我們之前用printf的時(shí)候,其實(shí)就是在往標(biāo)準(zhǔn)輸出流中寫入字符串;用scanf的時(shí)候,其實(shí)就是函數(shù)在從標(biāo)準(zhǔn)輸入流中讀取字符串。當(dāng)然,我們寫的程序也不可能一直都是正確的,警告和報(bào)錯(cuò)的情況時(shí)有發(fā)生,這個(gè)時(shí)候其實(shí)就是對標(biāo)準(zhǔn)錯(cuò)誤輸出中寫入數(shù)據(jù)。

這三個(gè)流,我們就將它們稱為:「標(biāo)準(zhǔn)流」

C語言分別為這三個(gè)標(biāo)準(zhǔn)流提供了對應(yīng)的文件指針:stdin,stdout,stderr

比如打開文件失敗的時(shí)候,就可以這樣顯示:

...    fputs('打開文件失敗!\n'stderr); exit(EXIT_FAILURE);...

這樣就不用printf這種“不專業(yè)”的錯(cuò)誤指示方法了。

打開文件失??!

錯(cuò)誤處理

每個(gè)流的內(nèi)部都有兩個(gè)指示器。一個(gè)是「文件結(jié)束指示器feof」,當(dāng)遇到文件末尾時(shí)被設(shè)置;另一個(gè)是「錯(cuò)誤指示器ferror」,當(dāng)讀寫文件出錯(cuò)時(shí)被設(shè)置。

...if (ferror(fp)){    fputs('出錯(cuò)了!\n'stderr);}...

而使用clearerr可以人為地清除兩個(gè)指示器的狀態(tài):

...    clearerr(fp);...

錯(cuò)誤指示器只能判斷是否出了錯(cuò)誤,但具體是什么錯(cuò)誤,那就要看errno和perror了。

首先看errno。這個(gè)函數(shù)包含在errno.h這個(gè)頭文件中。它會返回一個(gè)錯(cuò)誤碼。

#include <errno.h>...printf('打開文件失敗:%d\n', errno);...

舉個(gè)例子:

打開文件失?。?

但是這個(gè)錯(cuò)誤代碼不是所有人都知道它的含義。所以C語言又提供了一個(gè)函數(shù)perror,它可以直接用文字來提示我們錯(cuò)誤的地方。

#include <stdio.h>...perror('打開文件失敗,原因是');...

結(jié)果是這樣的:

打開文件失敗,原因是:No such file or directory

中間的冒號是自動加上的。

或許以后在你的開發(fā)生涯中,用的最多的不是C語言,但這門語言對你帶來的提升,那是不可忽視的。最后,祝各位學(xué)有所成!

關(guān)注我,帶你遨游代碼的世界

獲取完整視頻教程,可以關(guān)注B站:https://www.bilibili.com/video/BV1QE411y7v4

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
文件操作 FILE結(jié)構(gòu)體(C語言版)
python基礎(chǔ)教程之popen函數(shù)操作其它程序的輸入和輸出示例
C語言文件操作之----文件的讀寫
C語言快速入門系列(8)
第十三章 文 件
C 的文件操作
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服