在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. Django-Ajax组件

    Ajax Ajax简介 AJAX(Asynchronous Javascript And XML),翻译成中文为"异步Javascript和XML".即使用Javascript语言 ...

  2. 【HDU 3037】Saving Beans(卢卡斯模板)

    Problem Description Although winter is far away, squirrels have to work day and night to save beans. ...

  3. javaweb 开发所需工具和入门教程文档等

    下载网址 1.JDK1.8下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.ht ...

  4. Python接口测试之moco

    在现在的软件开发过程中,特别是app的部分,需要的很多数据以及内容,都是来自server端的API,但是不能保证 在客户端开发的时候,api在server端已经开发完成,专门等着前端来调用,理想的情况 ...

  5. pycharm配置git--图文教程

    1.     下载git客户端 2.     File->Default Setting-> Version Control->Git 3.     Path to Git exec ...

  6. PTA 05-树7 堆中的路径 (25分)

    题目地址 https://pta.patest.cn/pta/test/15/exam/4/question/713 5-5 堆中的路径   (25分) 将一系列给定数字插入一个初始为空的小顶堆H[] ...

  7. [Go]GOPATH相关知识点

    在成功安装好Go之后,执行命令 go env 就可以看到有关go的一些环境变量,其中比较关键的是GOROOT.GOPATH和 GOBIN 1.设置GOPATH环境变量有什么意义? GOPATH是指:指 ...

  8. 洛谷P1077 摆花

    题目描述 小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共m盆.通过调查顾客的喜好,小明列出了顾客最喜欢的n种花,从1到n标号.为了在门口展出更多种花,规定第i种花不能超过ai盆,摆花时 ...

  9. hdu 1879

    #include<stdio.h> #include<stdlib.h> #define N 100 struct node { int x,y,dis; }road[N*N] ...

  10. SpringBoot自动配置的源码解析

    首先,写源码分析真的很花时间,所以希望大家转的时候也请注明一下,Thanks♪(・ω・)ノ SpringBoot最大的好处就是对于很多框架都默认的配置,让我们开发的时候不必为了大一堆的配置文件头疼,关 ...