open和fopen的区别以及两者打开文件后操作的区别

概念

open

属于不带缓存的文件IO操作,是通过调用非标准库(libc库)函数来间接调用系统调用实现的IO操作。这种操作方式,可以高效完成文件输入输出,它以文件标识符作为文件唯一性的判断依据。但由于这种操作不是ANSI C标准的,与系统有关,所以移植起来会有问题。当然,频繁操作的话开销也是个问题。

fopen

带缓存的IO操作是在不带缓存的基础上封装了一层,维护了一个输入输出缓冲区,使之能跨OS,成为ANSI C标准,成为标准IO库。由于缓冲区的存在,使得不用频繁地调用系统调用,可以减小系统开销,但是响应速度也会受到影响。

两者比较

不带缓存的方式会频繁地进行用户态和内核态的切换,高效但是需要程序员自己维护;带缓存的方式因为有了缓冲区,不是非常高效,但是易于维护。

表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列快;如果随机访问文件,open要比fopen快。且由于设备文件不可以当成流式文件来用,只能用open。所以,一般用fopen打开普通文件,用open打开设备文件。


操作

Linux里面有一个struct file结构体,定义在include/Linux/fs.h,文件结构体对应一个打开了的文件,每一个打开的文件在内核空间里面都对应了一个文件结构体。它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,struct file的指针通常被命名为file或filp。

struct file {

  union {

        struct list_head fu_list; //文件对象链表指针linux/include/linux/list.h

        struct rcu_head fu_rcuhead; //RCU(Read-Copy Update)是Linux 2.6内核中新的锁机制

   } f_u;

  struct path f_path; //包含dentry和mnt两个成员,用于确定文件路径

  #define f_dentry f_path.dentry //f_path的成员之一,当前文件的dentry结构

  #define f_vfsmnt f_path.mnt //表示当前文件所在文件系统的挂载根目录

  const struct file_operations *f_op; //与该文件相关联的操作函数

  atomic_t f_count; //文件的引用计数(有多少进程打开该文件)

  unsigned int f_flags; //对应于open时指定的flag

  mode_t f_mode; //读写模式:open的mod_t mode参数

       loff_t     f_pos;//当前文件指针位置

  off_t f_pos; //该文件在当前进程中的文件偏移量

  struct fown_struct f_owner; //该结构的作用是通过信号进行I/O时间通知的数据。

  unsigned int f_uid, f_gid;// 文件所有者id,所有者组id

  struct file_ra_state f_ra; //在linux/include/linux/fs.h中定义,文件预读相关

  unsigned long f_version;//记录文件的版本号,每次使用之后递增

  #ifdef CONFIG_SECURITY

       void *f_security;

  #endif

  /* needed for tty driver, and maybe others */

  void *private_data;//使用这个成员来指向分配的数据

  #ifdef CONFIG_EPOLL

  /* Used by fs/eventpoll.c to link all the hooks to this file */

      struct list_head f_ep_links;

      spinlock_t f_ep_lock;

  #endif /* #ifdef CONFIG_EPOLL */

  struct address_space *f_mapping;

  };

每个进程在PCB(进程控制块)中都维护着一张文件描述符表,文件描述表中每个表项都有一个指向已打开文件(上面提到的file结构体)的指针。

关于返回值。open返回的是一个描述符,这个描述符对应的就是PCB中文件描述符表里面的描述符,操作这个值即可操作对应文件。fopen返回的是一个FILE类型的指针(与上面的file结构体不一样),这个类型的结构体包含了缓冲区的部分,以及描述符,所以也很好理解fopen是在open的基础上封装了一层缓冲区。

#ifndef _FILE_DEFINED
struct _iobuf {
        char *_ptr;          //文件输入的下一个位置 
        int   _cnt;          //当前缓冲区的相对位置 
        char *_base;         //指基础位置(即是文件的其始位置)
        int   _flag;         //文件标志
        int   _file;         //文件的有效性验证(文件描述符) 
        int   _charbuf;      //检查缓冲区状况,如果无缓冲区则不读取
        int   _bufsiz;       //缓冲区大小
        char *_tmpfname;     //临时文件名
        };
typedef struct _iobuf FILE;

你可能感兴趣的:(缓存,linux,libc,ansi)