文章出處:http://blog.csdn.net/thefutureisour/article/details/8133931
在C語言中,文件的操作是通過FILE結構體進行了,具體實現時,先利用fopen返回一個指向FILE結構體的指針:
FILE *fopen( const char *filename, const char *mode );filename:文件名,mode:打開的模式,規定了是可讀、可寫、追加之類的屬性。
"r":可讀,如果文件不存在,fopen調用失敗
"w":可寫,如果文件存在,那麼原來的內容會被銷燬。
"a":在文件尾追加,在新的數據寫到文件裏之前,不改變EOF標記,如果文件不存在,創建一個新的文件。
"r+":可讀可寫,文件必須存在。
"w+":打開一個空文件用來讀寫,如果文件存在,則內容被銷燬。
"a+":可讀可追加,在新的數據寫到文件裏之前,改變EOF標記;如果文件不存在,創建一個新的文件。
如果調用失敗,返回一個空指針。
size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
buffer:寫入文件的內容;size:每一項的大小;count:寫入了多少項;stream:指向文件的指針。返回值爲寫入的總的字節數。
先看一個簡單的例子:
- int main()
- {
- FILE *pFile = fopen("1.txt","w");
- fwrite("hello,world!",1,strlen("hello,world!"),pFile);
- return 0;
- }
其實,我們完全可以手動的關閉文件:
int fclose( FILE *stream );
stream:指向文件的指針。如果成功,返回0;失敗返回EOF。這樣,當執行完關閉文件後,文件裏面就有值了。
有時候,我們會反覆讀寫一個文件,而且每次讀寫後都希望立即看到結果。這時候每次讀完就關閉,然後重新打開的話實在太麻煩了,有沒有簡單的辦法呢?可以使用fflush來刷新流:
int fflush( FILE *stream );
stream:指向文件的指針。
如果我們在接着向文件中寫入數據:
fwrite("歡迎訪問",1,strlen("歡迎訪問"),pFile);
我們會發現,新寫入的數據會在原來文件的末尾後加上。可系統是如何知道原來文件的末尾在哪裏呢?
我們先看看FILE結構體:
- struct _iobuf {
- char *_ptr; //文件輸入的下一個位置
- int _cnt; //當前緩衝區的相對位置
- char *_base; //指基礎位置(應該是文件的其始位置)
- int _flag; //文件標誌
- int _file; //文件的有效性驗證
- int _charbuf; //檢查緩衝區狀況,如果無緩衝區則不讀取
- int _bufsiz; //文件的大小
- char *_tmpfname;//臨時文件名
- };
- typedef struct _iobuf FILE;
int fseek( FILE *stream, long offset, int origin );
stream:指向文件的指針,offset:偏移量;origin:初始位置,它有3種取法:
SEEK_CUR:當前位置
SEEK_END:文件尾
SEEK_SET:文件頭
如果我們這樣使用:
- fwrite("hello,world!",1,strlen("hello,world!"),pFile);
- fflush(pFile);
- fseek(pFile,0,SEEK_SET);
- fwrite("歡迎訪問",1,strlen("歡迎訪問"),pFile);
我們使用ftell函數獲取當前文件指針的位置:
long ftell( FILE *stream );
返回值爲與文件頭的偏移量。
通過它,我們可以獲得文件的長度。
讀取文件使用的是fread函數:
size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
buffer指明瞭讀取的文件儲存在哪裏,size表明每個項的大小,count表明了讀多少項,stream是指向FILE類型的指針。返回值爲實際讀取的字節數。
當然,在你讀取文件之前,最好確保文件指針指向的是文件的頭部,通過rewind函數來讓指針復位:
void rewind( FILE *stream );
stream:指向文件的指針
下面看一個綜合的例子:
- int main()
- {
- FILE *pFile = fopen("1.txt","w+");
- fwrite("hello,world!",1,strlen("hello,world!"),pFile);
- fflush(pFile);
- fseek(pFile,0,SEEK_SET); //文件指針設爲起點,寫操作覆蓋原來的內容
- fwrite("歡迎訪問",1,strlen("歡迎訪問"),pFile);
- fseek(pFile,0,SEEK_END); //文件指針設爲終點
- int len = ftell(pFile); //獲取文件字節數
- char* ch = (char*)malloc(sizeof(char)* (len+1)); //分配內存,多一個字節
- memset(ch,0,(len+1)); //清0
- // fseek(pFile,0,SEEK_SET); //文件指針指向頭部
- rewind(pFile);
- fread(ch,1,len,pFile); //讀取文件
- fclose(pFile);
- printf("%s",ch);
- return 0;
- }
基本的內容就是這麼多,下面看一個細節問題:
- int main()
- {
- FILE *pFile = fopen("2.txt","w+");
- char ch[3];
- ch[0] = 'a';
- ch[1] = 10;
- ch[2] = 'b';
- fwrite(ch,1,3,pFile);
- fflush(pFile);
- char buf[100];
- memset(buf,0,100);
- rewind(pFile);
- fread(buf,1,3,pFile);
- fclose(pFile);
- printf("%s",buf);
- return 0;
- }
我們看看文件的16進制:61 0D 0A 62 ,其中61、62對應的是a和b,0A對應的是10,那麼0D對應的是什麼呢?答案是回車字符,這個字符是系統自動加進去的。而在讀取文件時,我們也並沒有讀取個字節,只用讀取3個字節,就能正確獲取內容了。
與這個問題相關的一組概念是:二進制文件和文本文件。C語言中,默認是以文本的方式打開文件的,如果我們使用二進制文件方式打開:
FILE *pFile = fopen("2.txt","w+b");
也不會出什麼問題,只不過文件的大小爲3個字節,對應的16進製爲:61 0A 62。但是如果你在寫入時使用的是文本文件,而讀取時使用的是二進制文件,就會出錯,因爲它會把回車當做一個字符輸出。總而言之,讀和寫的方式要對應。