在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: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

通过以上代码,我们就在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: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

可以看到,当我们使用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" );
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

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

C编程中fread 、fwrite 用法总结的更多相关文章

  1. Shell编程中Shift的用法

    Shell编程中Shift的用法 位置参数可以用shift命令左移.比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1.$2.$3丢弃,$0不移动.不带参数的shif ...

  2. Shell编程中Shift的用法【转】

    本文转载自:http://www.cnblogs.com/image-eye/archive/2011/08/20/2147153.html Shell编程中Shift的用法 位置参数可以用shift ...

  3. 详解shell编程中2>&1用法

    在使用 linux 命令或者 shell 编程时,这个用法常会遇到 2>&1 下面看一个命令示例,然后分析下他是如何工作的: ls foo > /dev/null 2>&am ...

  4. shell编程中的select用法

    select 语句 select表达式是bash的一种扩展应用,擅长于交互式场合.用户可以从一组不同的值中进行选择: select var in ... ; do break; done .... n ...

  5. bash 编程中循环语句用法

    1.if 是单分支语句,使用格式如下: if condition ; then statement ….. fi 2.if … else 是双分支语句,使用格式如下: if condition ; t ...

  6. Shell编程中Shift的用法(转)

    位置参数可以用shift命令左移.比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1.$2.$3丢弃,$0不移动.不带参数的shift命令相当于shift 1. 非常 ...

  7. Shell编程中while与for的区别及用法详解【转】

    在shell编程中经常用到循环,常用的循环有for和while循环两种.while循环默认以行读取文件,而for循环以空格读取文件切分文件,本篇就结合现网的一些使用示例说说二者的用法和区别. 一.常用 ...

  8. (转)轻松掌握shell编程中数组的常见用法及示例

    缘起:在老男孩进行linux培训shell编程教学中,发现不少水平不错的网友及同学对数组仍然很迷糊,下面就给大家分享下数组的用法小例子,希望能给大家一点帮助.其实SHELL的数组很简单,好用.我们学习 ...

  9. shell编程系列21--文本处理三剑客之awk中数组的用法及模拟生产环境数据统计

    shell编程系列21--文本处理三剑客之awk中数组的用法及模拟生产环境数据统计 shell中的数组的用法: shell数组中的下标是从0开始的 array=("Allen" & ...

随机推荐

  1. linux 服务器 php vue项目部署流程总结

    服务器配置 购买阿里云服务器 (选择ubuntu 16系统 / 内存2G以上) 安全策略, 入规则: 添加端口 20,21,22, 80, 443, 3306, 8080, 安装宝塔 wget -O ...

  2. 小白安装Python环境详细步骤!

    昨天,有小伙伴向我反映,他对我说“你好像还没教过我安装Python的吧?”听到这句话,我不禁汗颜起来,我的确好像没太注意Python学习的基础了,一直发各种爬虫与初学者看不懂的代码,在此我要向我的读者 ...

  3. Postfix mail for azengna.com loops back to myself -solve

    设置 /etc/postfix/main.cf 原配置 mydestination = $myhostname, localhost.$mydomain, localhost 改为 mydestina ...

  4. Root of AVL Tree

    04-树5 Root of AVL Tree(25 分) An AVL tree is a self-balancing binary search tree. In an AVL tree, the ...

  5. javax.servlet.jsp.JspTagException: Neither BindingResult nor plain target object for bean (蛋疼死我了)

    1为抛出异常原因,2为异常解决方法. 原因:   进入spring:bind标签源码你可以看到 Object target = requestContext.getModelObject(beanNa ...

  6. 【Codeforces 1141E】Superhero Battle

    [链接] 我是链接,点我呀:) [题意] 题意 [题解] 二分最后轮了几圈. 二分之后直接o(N)枚举具体要多少时间即可. 注意爆long long的情况. 可以用对数函数,算出来有多少个0 如果大于 ...

  7. 【转】关于RabbitMQ

    1      什么是RabbitMQ? RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面表现不 ...

  8. HDU-2647 Reward ,逆拓排。

    Reward 发工资,以前看过这题,做没做忘了(应该是没做). 很明显的拓排.但数据范围这么大,吓得我当时就不敢动手.后来找题解发现还是相当于两层循环(are you kidding me?)当时卡在 ...

  9. bzoj 3207 花神的嘲讽计划Ⅰ 主席树+hash

    花神的嘲讽计划Ⅰ Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3112  Solved: 1086[Submit][Status][Discuss] ...

  10. vs code 使用心得

    Jetbrains 家族的软件适合java,python开发,但是对与rust,shell等的开发,则显得有些臃肿,需要一款轻快的编辑器,经过挑选,在sublime3 与 vs code 中选则了vs ...