open, read, write/fopen,fread,fwrite区别_c write和read的效率_麦子_hsx的博客-程序员宅基地

技术标签: readfread  writefwrite  区别  openfopen  



UNIX环境下的C 对二进制流文件的读写有两套班子:1) fopen,fread,fwrite ; 2) open, read, write


在介绍之前先简单的说一下 缓冲区和非缓冲区
1.缓冲文件系统
缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”, 装满后再从内存“缓冲区”依此读入接收的变量。执行写文件的操作时


,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存 “缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来


说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等


2.非缓冲文件系统
缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数 据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行


读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度 快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。本书只作简单介绍。open, close, read, write, getc, getchar, putc, putchar 等。

open&&fopen

open 是POSIX 定义的,是系统调用 返回的是文件描述符(int型整数),open系列只能用在 POSIX 的操作系统上。
fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api,返回的是一个指向文件结构的指针,fopen系列更具有可移植性


使用open系列函数需要"#include <fcntl.h>" ,链接时要之用libc(-lc)
使用fopen系列函数需要"#include <sdtio.h>"


open可以指定权限.
fopen不能指定要创建文件的权限.


open与 read, write 等配合使用, 
fopen与 fread, fwrite等配合使用。


前者无缓冲,后者有缓冲


open每次都需要进行内核态和用户态的切换;
fopen在用户态下就有了缓存,在进行read和write的时候减少了用户态和内核态的切换,
表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列快;如果随机访问文件open要比fopen快。


open属于低级IO,fopen是高级IO。由于能更多地与操作系统打交道,open系列可以访问更改一些fopen系列无法访问的信息,如查看文件的读写权限,这些额外的功能通常因系统而异。


文件描述符是linux下的一个概念,linux下的一切设备都是以文件的形式操作.如网络套接字、管道、硬件设备等。当然包括操作文件。
设备文件不可以当成流式文件来用,只能用open
fopen是用来操纵正规文件的,并且设有缓冲的,跟open还是有一些区别
一般用fopen打开普通文件,用open打开设备文件




用法举例:
函数名: fopen 
功  能: 打开一个流 
用  法: FILE *fopen(char *filename, char *type); 
程序例:
#include <stdlib.h> 
#include <stdio.h> 
#include <dir.h>
int main(void) 

    char *s; 
    char drive[MAXDRIVE]; 
    char dir[MAXDIR]; 
    char file[MAXFILE]; 
    char ext[MAXEXT]; 
    int flags;
    s=getenv("COMSPEC"); /* get the comspec environment parameter */ 
    flags=fnsplit(s,drive,dir,file,ext);
    printf("Command processor info:\n"); 
    if(flags & DRIVE) 
       printf("\tdrive: %s\n",drive); 
    if(flags & DIRECTORY) 
       printf("\tdirectory: %s\n",dir); 
    if(flags & FILENAME) 
       printf("\tfile: %s\n",file); 
    if(flags & EXTENSION) 
       printf("\textension: %s\n",ext);
    return 0; 

函数名: open 
功  能: 打开一个文件用于读或写 
用  法: int open(char *pathname, int access[, int permiss]); 
程序例:
#include <string.h> 
#include <stdio.h> 
#include <fcntl.h> 
#include <io.h>
int main(void) 

   int handle; 
   char msg[] = "Hello world";
   if ((handle = open("TEST.$$$", O_CREAT | O_TEXT)) == -1) 
   { 
      perror("Error:"); 
      return 1; 
   } 
   write(handle, msg, strlen(msg)); 
   close(handle); 
   return 0; 
}


read/write和fread/fwrite区别

read在linux/unix中读二进制与普通文件没有区别.
fread可以读一个结构.


read是带了缓存但是指的是系统层或者说kernel层,当然也可能不带,比如直接DMA,由驱动决定。
fread带缓存指的是应用层带缓存,


read是内核的缓冲。
fread是标准库的缓冲,


read/write如果可以精确控制一次读写的数据,则会比fread/fwrite更加高效


read/write对应Linux中的system call, 而fread/fwrite则可以说是对read/write的又一次封装,read/write更加原生,如果不考虑跨平台,建议多使用read/write.


read函数从打开的设备或文件中读取数据。
#include <unistd.h>  ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0
参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读


写位置是用户空间I/O缓冲区中的位置。


fread就是通过read来实现的,fread是C语言的库,而read是系统调用
但是差别在read每次读的数据是调用者要求的大小,比如调用要求读取10个字节数据,read就会读10个字节数据到数组中,而fread不一样,为了加快读的速度,fread每次都会读比要求更多的数据,然后放到缓冲区中,这样


下次再读数据只需要到缓冲区中去取就可以了。


如果文件的大小是8k。
你如果用read/write,且只分配了2k的缓存,则要将此文件读出需要做4次系统调用来实际从磁盘上读出。
如果你用fread/fwrite,则系统自动分配缓存,则读出此文件只要一次系统调用从磁盘上读出。
也就是用read/write要读4次磁盘,而用fread/fwrite则只要读1次磁盘。效率比read/write要高4倍。
如果程序对内存有限制,则用read/write比较好。
都用fread 和fwrite,它自动分配缓存,速度会很快,比自己来做要简单。如果要处理一些特殊的描述符,用read 和write,如套接口,管道之类的
系统调用write的效率取决于你buf的大小和你要写入的总数量,如果buf太小,你进入内核空间的次数大增,效率就低下。而fwrite会替你做缓存,减少了实际出现的系统调用,所以效率比较高。
如果只调用一次(可能吗?),这俩差不多,严格来说write要快一点点(因为实际上fwrite最后还是用了write做真正的写入文件系统工作),但是这其中的差别无所谓。
============ 


举个例子:


做如下步骤的操作:


打开文件
读文件的0k~4k(read or fread)
其他操作
读文件的1k~3k(read or fread)
关闭文件
这时候如果是read,步骤4要调用内核;而如果是fread,因步骤2在应用层已经缓冲所需内容,数据会直接返回,无需再次调用内核

fread每次会读取一个缓冲区大小的数据,32位下一般是4096个字节,相当于调用了read(fd,buf,4096)

比如需要读取512个字节数据,分4次读取,
调用read就是:
for(i=0; i<4; ++i)
read(fd,buf,128)
一共有4次系统调用


而fread一次就读取了4096字节放到缓冲区了,所以省事了
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/maizi_hsx/article/details/78726779

智能推荐

【nginix】ubuntu18.04:生成CMakeLists.txt_ubuntu 18.04 新建的文件夹catkin_make 后,cmakelists.txt和别的_等风来不如迎风去的博客-程序员宅基地

github.com/i-rinat/nginx-cmake.git 大神的脚本带flv module 编译./configure --prefix=/home/zhangbin/simu/las/flvnginx/out --with-debug --with-http_stub_status_module --add-module=moudle/nginx-http-flv-module编译过程:zhangbin@UbVmFsn:~/simu/las/flvngin.._ubuntu 18.04 新建的文件夹catkin_make 后,cmakelists.txt和别的工程文件一样

一个app跳转到另一个app的指定功能_怎样让软件跳转到自定义应用-程序员宅基地

开发有时需要在一个应用中启动另一个应用,比如Launcher加载所有的已安装的程序的列表,当点击图标时可以启动另一个应用,一般我们知道了另一个应用的包名和MainActivity的名字之后便可以直接通过如下代码来启动。网上看了很多文章,都是说用intent跳转,方法如下:[java] view plain copyInte_怎样让软件跳转到自定义应用

平常使用的JDK和Open JDK有什么区别?-程序员宅基地

使用过LINUX的人都应该知道,在大多数LINUX发行版本里,内置或者通过软件源安装JDK的话,都是安装的openjdk,那么到底什么是openjdk,它与sun jdk有什么关系和区别呢?文章目录0.简洁版回答1.历史上的原因2.关于JDK和OpenJDK的区别,可以归纳为以下几点:2.1 授权协议的不同2.2 OpenJDK不包含Deployment(部署)功能:2.3 OpenJDK源代码...

程序员宅基地的第一次签到_刚注册的csdn账号可以签到吗-程序员宅基地

第一天之前找资料、看博客的时候,经常能看到 程序员宅基地的文章,但是一直没有注册账号。终于,昨天做了之前一直想做的事情。这是我在 CSDN 的第一篇文章,记录时间: 2021-5-11 09:53:51加油,奥利给~..._刚注册的csdn账号可以签到吗

pecl 安装指定版本php扩展(swoole)_pecl 指定php版本_CRMEB定制开发的博客-程序员宅基地

1.pecl 搜索扩展包(这里以安装swoole 1.9.23 为例)详细教程:http://github.crmeb.net/u/defu通过搜索进入扩展包页面 https://pecl.php.net/package/swoole找到需要安装的版本 swoole-1.9.23.tgz (https://pecl.php.net/get/swoole-1.9.23.tgz)2.pecl 安装扩展包执行安装 pecl install https://pecl.php.net/get/swoole_pecl 指定php版本

两个linux内核rootkit--之二:adore-ng _内核 rootkit linux-程序员宅基地

转自:http://blog.csdn.net/dog250/archive/2010/02/09/5303688.aspx 这个rootkit使用的技术不比前一个,它不是拦截系统调用,而是拦截具体文件系统的回调函数,本身文件系统的回调函数就是动态注册的,很是不确定,那么反黑软件自然就不能简单下结论说这个函数被黑掉了,因此这个rootkit看来比前一个略胜一筹,自然的,既然是内核模块,那么_内核 rootkit linux

随便推点

Android开发网上的一些重要知识点_elapsedrealtime jni-程序员宅基地

1. android单实例运行方法我们都知道Android平台没有任务管理器,而内部App维护者一个Activity history stack来实现窗口显示和销毁,对于常规从快捷方式运行来看都是startActivity可能会使用FLAG_ACTIVITY_NEW_TASK标记来打开一个新窗口,比如Launcher,所以考虑单任务的实现方法比较简单,首先Android123纠正下大家一种错误_elapsedrealtime jni

《创新思维训练》2021网课章节测验及答案_创新思维训练王竹立章节测验答案-程序员宅基地

本书旨在提高创新思维能力,让你的大脑“动起来”,使你在遭遇世界500强及各类综合素质测试的“偏题”和“怪题”时,不再感到无从下手,而是能够运用本书中讲到的各种思维方法,通过思维的灵活转换,成功破解各种面试难题并全面开发自己的创新潜力,以适应时代的需要。..._创新思维训练王竹立章节测验答案

eclipse小技巧-程序员宅基地

最近写CODE的时候,遇到个问题:得到一个JAVA文件所在的插件路径.问题倒是很快解决了.可气人的是这个问题好久之前我已经问过一次了.没想到又忘了.郁闷!!!于是决定写篇文章,把ECLIPSE开发中的小方法集中起来,方便自己查询,也可以给刚入门的程序员个提示.对于同时也希望谁有小的技巧能共享一下.我也算是抛砖引玉吧.1.得到某PLUGIN的路径: Platform.getBun...

大数据导入Mysql踩坑_大数据是否使用myscol_顾秋生的博客-程序员宅基地

大数据导入Mysql踩坑涉及技术简述踩坑及处理后记涉及技术简述微服务架构,k8s部署管理,大数据导入数据库的功能涉及两个服务,一个负责csv文件的定时读取,一个负责文本的处理及入库。读取服务会将文件内容按OLT粒度涉及的硬件消息,分为约5000条5~10kb的消息发送到kafka指定Topic的同一个分片,此项目分区pattern只设置了2个。均匀分发消息。处理入库服务则是从消息队列读取消息。然后线程池并发处理。踩坑及处理我们的目的是,尽量快速处理约1.5GB的csv文件,具体到数据库的reco_大数据是否使用myscol

使用vuex存储状态页面刷新后数据丢失怎么处理_vue sessionstorage 跨项目 多页面 跳转 丢失-程序员宅基地

vue是单页面应用,页面切换都是在一个页面跳转路由,因此sessionStorage较为合适。(sessionStorage的生命周期是在仅在当前会话下有效)所以应该在页面加载的时候将store里面的状态传入进sessionStorage里面在app.vue内假如以下代码created() { // 在页面加载时读取sessionStorage里的状态信息,还原store if (sessionStorage.getItem('store')) _vue sessionstorage 跨项目 多页面 跳转 丢失

推荐文章

热门文章

相关标签