在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;
 
}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

通过以上代码,我们就在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);
}

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

可以看到,当我们使用memset了以后,读出了一大堆乱码,这是为什么呢?原因是我们在fwrite函数时写入的字节数是用strlen求得的,也就是说字符串最后的”并没有写到文件中去。所以我们从文件中读到buffer中时也自然没有”,因为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
", numwritten );
      fclose( stream );
 
   }
   else
      printf( "Problem opening the file
" );
 
   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
", numread );
      printf( "Contents of buffer = %.25s
", list );
      fclose( stream );
   }
   else
      printf( "File could not be opened
" );
}
 

.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, “Courier New”, courier, monospace; background-color: rgba(255, 255, 255, 1) }
.csharpcode pre { margin: 0 }
.csharpcode .rem { color: rgba(0, 128, 0, 1) }
.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }
.csharpcode .str { color: rgba(0, 96, 128, 1) }
.csharpcode .op { color: rgba(0, 0, 192, 1) }
.csharpcode .preproc { color: rgba(204, 102, 51, 1) }
.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }
.csharpcode .html { color: rgba(128, 0, 0, 1) }
.csharpcode .attr { color: rgba(255, 0, 0, 1) }
.csharpcode .alt { background-color: rgba(244, 244, 244, 1); 100%; margin: 0 }
.csharpcode .lnum { color: rgba(96, 96, 96, 1) }

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,如套接口,管道之类的