在C語言中進行文件操作時,我們經常用到fread()和fwrite(),用它們來對文件進行讀寫操作。下面詳細紹一下這兩個函數的用法。
我們在用C語言編寫程序時,一般使用標准文件系統,即緩沖文件系統。系統在內存中為每個正在讀寫的文件開辟“文件緩沖區”,在對文件進行讀寫時數據都經過緩沖區。要對文件進行讀寫,系統首先開辟一塊內存區來保存文件信息,保存這些信息用的是一個結構體,將這個結構體typedef為FILE類型。我們首先要定義一個指向這個結構體的指針,當程序打開一個文件時,我們獲得指向FILE結構的指針,通過這個指針,我們就可以對文件進行操作。例如:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char buffer[100] = "This is a test";
if((fp = fopen("c:\\example.txt", "w")) == 0)
{
printf("open failed!");
exit(1);
}
fwrite(buffer, 1, strlen("This is a test"), fp);
char a = 'c';
int b =1;
float c = 1.0;
int x = fprintf(fp,"%s%d%f",a,b,c);
printf("c: %d",x);
fclose(fp);
fflush(stdin);
getchar();
return 0;
}
通過以上代碼,我們就在c盤的根目錄下建立了一個名為example擴展名為.txt的文件,我們打開可以看到上面寫上了This is a test。當我們對它將它讀出時,用如下代碼:
#include <stdio.h>
#include <memory.h>
int main()
{
FILE *fp; int len;
char buffer[100];
/*memset(buffer, 1, 100); */
if((fp = fopen("c:\\example.txt", "r")) == 0)
{
printf("open failed!");
exit(1);
}
fseek(fp, 0L, SEEK_END);
len = ftell(fp);
rewind(fp);
fread(buffer, 1, len , fp);
printf("%s",buffer);
fclose(fp);
getchar();
return (0);
}
可以看到,當我們使用memset了以后,讀出了一大堆亂碼,這是為什么呢?原因是我們在fwrite函數時寫入的字節數是用strlen求得的,也就是說字符串最后的'\0'並沒有寫到文件中去。所以我們從文件中讀到buffer中時也自然沒有'\0',因為buffer中的數是隨機的,除非buffer中最后一個字符的下一個數恰好隨機到0(可能性很小,這里用memset將它排除),否則以%s將buffer中的字符輸出時遇不到0,所以亂碼產生。解決的辦法有很多,你可以在向文件寫數據時多寫入一個字節,系統會自動寫入0,fwrite(buffer, 1, strlen("This is a test")+1, fp);這樣讀出時最后就有一個0了。或者讀出操作完成后,在最后一個字符后面補上一個0:buffer[len] = 0;這樣問題也可得到解決。
size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
buffer : 數據存儲的地址
size : 要讀取的字節的大小
count : 要讀取多少個size大小
stream : 等待被讀取的數據源,它是一個指向FILE結構的文件指針
fread 如果讀取成功,則返回count的大小,如果還沒有讀取count個size大小的數據時,就以及讀取完了整個文件,到了文件結尾的地方了,此時返回的值就要必count小,或者在讀取的過程出錯的話,返回的值也必count小,所以如果返回的值比count小時,可以通過feof()函數或ferror函數來判斷到底是讀取過程中出錯了還是已經讀取到了文件結尾的部分了。 如果size 或count 本身被設置為0, 則fread不做任何操作。
注:fread 函數的功能是從輸入流(input stream)中讀取count個size大小的字節數存儲到buffer中,關聯輸入流的文件指針的位置會隨着字節數的讀取而向前移動。如果輸入流是以文本模式打開的,那么單個換行符將會被替換成回車換行符,換行符的替換,不會影響到文件指針和返回值。如果遇到了錯誤,那么文件指針的當前位置和已讀取的不部分值都是不確定的。
size_t fwrite(const void *buffer, size_t size, size_t count , FILE *stream)
buffer: 指向被寫入的數據源指針
size: 每次寫入的字節數大小
count : 執行一次fwrite函數,最大可寫入 count個size大小的字節數
stream 指向等待寫入數據的文件指針,即文件被寫入的地址
如果寫入成功則返回count值。
fwrite的功能是將文件從buffer中寫入到output stream中去,每次寫入的字節數為size, 最多可寫入count次。
下面通過一個example 來進一步說明fread和fwrite的用法
/* FREAD.C: This program opens a file named FREAD.OUT and
* writes 25 characters to the file. It then tries to open
* FREAD.OUT and read in 25 characters. If the attempt succeeds,
* the program displays the number of actual items read.
*/
#include <stdio.h>
void main( void )
{
FILE *stream;
char list[30];
int i, numread, numwritten;
/* Open file in text mode: */
if( (stream = fopen( "fread.out", "w+t" )) != NULL )
{
for ( i = 0; i < 25; i++ )
list[i] = (char)('z' - i);
/* Write 25 characters to stream */
numwritten = fwrite( list, sizeof( char ), 25, stream );
printf( "Wrote %d items\n", numwritten );
fclose( stream );
}
else
printf( "Problem opening the file\n" );
if( (stream = fopen( "fread.out", "r+t" )) != NULL )
{
/* Attempt to read in 25 characters */
numread = fread( list, sizeof( char ), 25, stream );
printf( "Number of items read = %d\n", numread );
printf( "Contents of buffer = %.25s\n", list );
fclose( stream );
}
else
printf( "File could not be opened\n" );
}
Output Wrote 25 items Number of items read = 25 Contents of buffer = zyxwvutsrqponmlkjihgfedcb
|
fread 和fwrite函數
函數功能:用來讀寫一個數據塊
一般調用形式:
size_t fread(buffer, size , count, fp);
size_t fwrite(buffer, size , count , fp);
參數說明:
(1)buffer: 是一個指針,對fread來說,它是讀入數據的存放地址,對fwrite來說,是要輸出的數據的地址。
(2)size: 一次要讀寫的字節數(即fread 或fwrite 執行讀或寫的過程中,一次讀/寫的字節數大小為size個)
(3)count: 最多讀寫多少個size字節的數據(即調用一次fread或fwrite,它們在執行讀/寫的過程中,最多可以執行count次讀/寫操作,每次只能讀/寫size個字節大小的數據,為什么說最多可執行count次呢?比如希望調用fread()這條語句讀取K大小的數據,如果fread()中的size參數比K要小,那么就要多讀幾次才能讀取K大小的數據,這時我們就設置要讀取count次,那么最多可讀取count* size個字節大小的數據,但是這個count*size 不可能剛好是K的整數倍啊,這樣它必定是(count-i)*size + x = K, 這里的i 肯定是大於等於1的自然數,而x是小size且大於0的自然數,那么這樣到讀取完K大小的字節數還不需要執行count次操作。所以說最多執行count次)
(4)fp: FILE 型指針變量
注意:
1.完成一次寫操作(fwrite())后必須關閉流(fclose());
2.完成一次讀操作(fread())后,如果沒有關閉流(fclose()),則指針(FILE *fp)自動向后移動前一次讀寫的長度,不關閉流繼續下一次讀操作則接着上次的輸出繼續輸出。(例如stream = "12345678不關閉流接着輸出", 通過fread() 讀出到12345678就沒有讀取了,此時fp指針就指向了"8"這個位置,此時忘記關閉去流,那么下次還是用fp這個指針再通過fread()來讀取的話,那么此時的輸出是從"不"字開始輸出"不關閉流…",而不是從"1"開始輸出"12345678不關閉…")
fwrite和fread的應用舉例:
1.將一個字符串寫入文件:
char *str="hello,I am a test program!";
fwrite(str,sizeof(char),strlen(str),fp)
2.將一個字符數組寫入文件:
char str[]={'a','b','c','d','e'};
fwrite(str,sizeof(char),sizeof(str),fp)
3.將一個整型數組寫入文件:
int a[]={12,33,23,24,12};
先計算數組元素個數nmemb,之后
fwrite(a,sizeof(int),nmemb,fp)
read/write 和 fread/fwrite 有什么區別
實現機制是什么,兩者有什么聯系,對文件讀寫,兩者那個效率更高,速度更快
舉個例子:
如果文件的大小是8k。
你如果用read/write,且只分配了2k的緩存,則要將此文件讀出需要做4次系統調用來實際從磁盤上讀出。
如果你用fread/fwrite,則系統自動分配緩存,則讀出此文件只要一次系統調用從磁盤上讀出。
也就是用read/write要讀4次磁盤,而用fread/fwrite則只要讀1次磁盤。效率比read/write要高4倍。
如果程序對內存有限制,則用read/write比較好。
一般用來處理文件
都用fread 和fwrite,它自動分配緩存,速度會很快,比自己來做要簡單
如果要處理一些特殊的描述符,用read 和write,如套接口,管道之類的