C語(yǔ)言實(shí)現(xiàn)隨機(jī)讀寫(xiě)文件的函數(shù)詳解
在上一篇博客中,我詳細(xì)講解了如何使用C語(yǔ)言順序讀寫(xiě)文件。所謂順序讀寫(xiě),就是按照順序,挨個(gè)挨個(gè)的讀或者寫(xiě),換句話說(shuō),我必須先讀第一個(gè),再讀第二個(gè),接著讀第三個(gè),以此類(lèi)推,而不能一上來(lái)就讀第五個(gè)。這樣就不夠靈活,因?yàn)橛袝r(shí)候我們想讀寫(xiě)文件的任意位置。這就需要使用文件的隨機(jī)讀寫(xiě)。
文件的隨機(jī)讀寫(xiě),可以在文件中指定的任意位置讀或者寫(xiě)。這是怎么做到的呢?事實(shí)上,當(dāng)我們順序讀寫(xiě)文件時(shí),文件中會(huì)有一個(gè)指針記錄你讀(或者寫(xiě))到哪了。比如,一個(gè)文件里存著"abcdefg",當(dāng)我們打開(kāi)文件時(shí),這個(gè)指針默認(rèn)指向了第一個(gè)字符a,當(dāng)你用fgetc讀完a后,這個(gè)指針就指向了下一個(gè)字符b,當(dāng)你再使用fgetc讀取文件時(shí)就讀到了b,以此類(lèi)推。如果我們想一上來(lái)就讀e,除了按照順序讀寫(xiě)的方法,把前面的abcd全都讀走,還有一種方法,直接讓這個(gè)指針指向e,就可以了。
所以,文件的隨機(jī)讀寫(xiě),本質(zhì)上是改變記錄讀寫(xiě)位置的指針的指向,就能夠讀寫(xiě)任意位置了。下面我們將學(xué)習(xí)與此相關(guān)的3個(gè)函數(shù),分別是:
1.fseek,改變?cè)撝羔樀闹赶颉?/p>
2.ftell,獲取該指針相對(duì)于起始位置的偏移量。
3.rewind,使文件指針指向起始位置。
1.fseek
前面已經(jīng)劇透過(guò)了,fseek可以改變記錄讀寫(xiě)位置的指針的指向,從而實(shí)現(xiàn)文件的隨機(jī)讀寫(xiě)。該函數(shù)的聲明如下:
int fseek ( FILE * stream, long int offset, int origin );
第一個(gè)參數(shù)大家都很熟悉了,就是一個(gè)文件指針,告訴fseek我現(xiàn)在操作的是哪個(gè)文件。
第二個(gè)參數(shù),offset是偏移量的意思,大家先記住。第三個(gè)參數(shù),origin,顧名思義,即“起始位置”。后面兩個(gè)參數(shù)讓人摸不著頭腦,但是配合起來(lái)就很有意思了。
舉個(gè)例子:假設(shè)一個(gè)文件中存有abcdefg,當(dāng)你用fopen打開(kāi)這個(gè)文件時(shí),一個(gè)記錄讀寫(xiě)位置的指針就指向了起始位置,也就是指向了a。如果我想讀取第5個(gè)字符,即e呢?那我就要讓這個(gè)指針指向e,這樣再fgetc就能讀到e了。
我可以這樣算:e相對(duì)于起始位置a,向右偏移了4個(gè)字符,因?yàn)橄鄬?duì)于a,a自己的偏移量是0,b是1,c是2,d是3,e自然是4。那么,偏移量offset(fseek的第二個(gè)參數(shù))就是4,這個(gè)4是相對(duì)于起始位置的,這個(gè)“相對(duì)于”哪里,也就是origin(fseek的第三個(gè)參數(shù))的位置,此時(shí)origin就是“起始位置”,明白了吧。而fseek用一個(gè)宏SEEK_SET來(lái)表示“起始位置”,所以此時(shí)fseek的調(diào)用如下:
fseek(pf, 4, SEEK_SET);
下面我們來(lái)驗(yàn)證一下。先在工程目錄下創(chuàng)建一個(gè)文件,文件名是test.txt,然后在里面輸入abcdefg。
按照打開(kāi)文件->讀文件->關(guān)閉文件的順序,寫(xiě)代碼:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, 4, SEEK_SET); putchar(fgetc(pf)); fclose(pf); pf = NULL; return 0; }
打開(kāi)文件后,使用fseek讓記錄讀寫(xiě)位置的指針指向e,接著用fgetc讀取e并用putchar打印出來(lái),輸出結(jié)果如下:
我們就成功跳過(guò)了前面的abcd,直接讀取到e,實(shí)現(xiàn)了文件的隨機(jī)讀寫(xiě)。
當(dāng)然,讀取到e不止有這一種寫(xiě)法。fseek的第三個(gè)參數(shù)origin有三種取值,分別是:
1.SEEK_SET,表示起始位置。
2.SEEK_CUR,表示當(dāng)前指向的位置。
3.SEEK_END,表示文件末尾。
SEEK_SET和SEEK_CUR都很好理解,需要注意的是,SEEK_END不是指向最后一個(gè)字符,而是指向最后一個(gè)字符的下一個(gè)位置。比如,一個(gè)文件中存有abcdefg,SEEK_END不是指向g,而是指向g的下一個(gè)位置。所以同樣是讀到e,如果origin是SEEK_END,offset就應(yīng)該是-3,因?yàn)間的偏移量是-1,f是-2,所以e是-3。把上面代碼中的fseek的調(diào)用方式改一下,其他不變:
fseek(pf, -3, SEEK_END);
也可以讀到e,因?yàn)樵趫?zhí)行完上面這行代碼后,記錄讀寫(xiě)位置的指針就指向了e,所以讀取時(shí)就跳過(guò)了前面的abcd,直接讀到e。說(shuō)明一下,由于讀寫(xiě)前該指針指向了e,調(diào)用fgetc讀完e后,該指針就指向了e后面的f,也就是說(shuō),此時(shí)SEEK_CUR就指向了f,如果我們想讀到b呢?可以數(shù)一下,abcdefg,b相對(duì)于SEEK_CUR(指向f)的偏移量就是-4,如果像下面的代碼這樣寫(xiě):
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, -3, SEEK_END); // 指向e putchar(fgetc(pf)); // 讀完e后指向f fseek(pf, -4, SEEK_CUR); // 指向b putchar(fgetc(pf)); // 讀完b后指向c fclose(pf); pf = NULL; return 0; }
輸出結(jié)果如下:
2.ftell
我如果想知道此時(shí)記錄讀寫(xiě)位置的指針相對(duì)于起始位置的偏移量(即相對(duì)于SEEK_SET的偏移量)是多少,就可以問(wèn)問(wèn)ftell函數(shù)。該函數(shù)聲明如下:
long int ftell ( FILE * stream );
ftell會(huì)返回當(dāng)前相對(duì)于起始位置的偏移量。比如前面的例子中調(diào)用:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, -3, SEEK_END); // 指向e putchar(fgetc(pf)); // 讀完e后指向f fseek(pf, -4, SEEK_CUR); // 指向b putchar(fgetc(pf)); // 讀完b后指向c printf("\n%ld\n", ftell(pf)); fclose(pf); pf = NULL; return 0; }
由于此時(shí)記錄文件讀寫(xiě)位置的指針指向了c,偏移量是2(a為0,b為1,c為2),所以會(huì)輸出2。
3.rewind
rewind的作用是,讓指向文件讀寫(xiě)位置的指針指向文件的起始位置。該函數(shù)聲明如下:
void rewind ( FILE * stream );
其實(shí)非常簡(jiǎn)單,rewind(pf);和fseek(pf, 0, SEEK_SET);是等價(jià)的。
在前面的例子中,記錄文件讀寫(xiě)位置的指針左右橫跳,最后指向了c,此時(shí)ftell也返回了2,這時(shí)如果我rewind一下,該指針就又指向了起始位置,即a,再ftell就能知道偏移量回到了0,如果再fgetc,就能重新讀取到a了。代碼如下:
#include <stdio.h> int main() { FILE* pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, -3, SEEK_END); // 指向e putchar(fgetc(pf)); // 讀完e后指向f fseek(pf, -4, SEEK_CUR); // 指向b putchar(fgetc(pf)); // 讀完b后指向c printf("\n%ld\n", ftell(pf)); rewind(pf); printf("%ld\n", ftell(pf)); putchar(fgetc(pf)); // a fclose(pf); pf = NULL; return 0; }
輸出結(jié)果:
當(dāng)然,把上述代碼中的rewind(pf);換成fseek(pf, 0, SEEK_SET);的效果是一樣的。
總結(jié)
1.文件的隨機(jī)讀寫(xiě)本質(zhì)上是改變一個(gè)指向文件讀寫(xiě)位置的指針的指向。
2.使用fseek和rewind函數(shù)可以做到(1)這一點(diǎn)。其中,fseek需要知道該指針需要指向的新的位置,具體需要一個(gè)相對(duì)于某起始位置(origin)的偏移量(offset),其中origin可以取值為SEEK_SET(文件的起始位置),SEEK_END(文件的結(jié)束位置)和SEEK_CUR(當(dāng)前位置)。rewind函數(shù)會(huì)讓該指針直接指向SEEK_SET,所以rewind(pf);等價(jià)于fseek(pf, 0, SEEK_SET);。
3.使用ftell函數(shù)可以獲取當(dāng)前該指針相對(duì)于起始位置的偏移量。
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)隨機(jī)讀寫(xiě)文件的函數(shù)詳解的文章就介紹到這了,更多相關(guān)C語(yǔ)言隨機(jī)讀寫(xiě)文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VC++文件監(jiān)控之ReadDirectoryChangesW
文章主要介紹文件監(jiān)控的另一種實(shí)現(xiàn)方式,利用ReadDirectoryChangesW來(lái)實(shí)現(xiàn)文件的監(jiān)控,希望對(duì)大家有幫助2019-04-04用C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)掃雷小游戲
這篇文章主要為大家詳細(xì)介紹了用C語(yǔ)言簡(jiǎn)單實(shí)現(xiàn)掃雷小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08VC6.0代碼自動(dòng)提示 VC6.0在win7環(huán)境下代碼提示智能化
作為程序猿的你,是否已經(jīng)喜歡或習(xí)慣依賴(lài)IDE開(kāi)發(fā)環(huán)境呢,有了IDE環(huán)境,即使你想不起方法全名,只要知道某個(gè)前綴,或哪怕在提示列表中,一一查詢,也可以找到自己想找的方法或?qū)傩?/div> 2013-01-01最新評(píng)論