Linux--struct file结构体

struct file(file结构体):
  struct file结构体定义在include/linux/fs.h中定义。文件结构体代表一个打开的文件,系统中的每个打开的文件在内核空间都有一个关联的 struct file。

它由内核在打开文件时创建,并传递给在文件上进行操作的任何函数。在文件的所有实例都关闭后,内核释放这个数据结构。在内核创建和驱动源码中,

struct file的指针通常被命名为file或filp。其有两个非常重要的字段:文件描述符和缓冲区。

 文件描述符fd:

  fd只是一个小整数,在open时产生。起到一个索引的作用,进程通过PCB中的文件描述符表找到该fd所指向的文件指针filp。

文件描述符的操作(如:
open)返回的是一个文件描述符,内核会在每个进程空间中维护一个文件描述符表, 所有打开的文件都将通过此表中的文件描述符来引用; 
而流(如: fopen)返回的是一个FILE结构指针, FILE结构是包含有文件描述符的,FILE结构函数可以看作是对fd直接操作的系统调用的封装, 它的优点是带有I/O

缓存。

  每个进程在PCB(Process Control Block)即进程控制块中都保存着一份文件描述符表,文件描述符就是这个表的索引,文件描述表中每个表项都有一个指

向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。

缓冲区:

A)缓冲区机制

根据应用程序对文件的访问方式,即是否存在缓冲区,对文件的访问可以分为带缓冲区的操作和非缓冲区的文件操作:

  a) 带缓冲区文件操作:高级标准文件I/O操作,将会在用户空间中自动为正在使用的文件开辟内存缓冲区。

  b) 非缓冲区文件操作:低级文件I/O操作,读写文件时,不会开辟对文件操作的缓冲区,直接通过系统调用对磁盘进行操作(读、写等),当然用于可以在自己

的程序中为每个文件设定缓冲区。

两种文件操作的解释和比较:

  1、非缓冲的文件操作访问方式,每次对文件进行一次读写操作时,都需要使用读写系统调用来处理此操作,即需要执行一次系统调用,执行一次系统调用将涉

及到CPU状态的切换,即从用户空间切换到内核空间,实现进程上下文的切换,这将损耗一定的CPU时间,频繁的磁盘访问对程序的执行效率造成很大的影响。

  2、ANSI标准C库函数 是建立在底层的系统调用之上,即C函数库文件访问函数的实现中使用了低级文件I/O系统调用,ANSI标准C库中的文件处理函数为了减

少使用系统调用的次数,提高效率,采用缓冲机制,这样,可以在磁盘文件进行操作时,可以一次从文件中读出大量的数据到缓冲区中,以后对这部分的访问就不需

要再使用系统调用了,即需要少量的CPU状态切换,提高了效率。

B)缓冲类型

标准I/O提供了3种类型的缓冲区。

  1、全缓冲区:这种缓冲方式要求填满整个缓冲区后才进行I/O系统调用操作。对于磁盘文件的操作通常使用全缓冲的方式访问。第一次执行I/O操作时,ANSI标

准的文件管理函数通过调用malloc函数获得需要使用的缓冲区,默认大小为8192。

  2、行缓冲区:在行缓冲情况下,当在输入和输出中遇到换行符时,标准I/O库函数将会执行系统调用操作。当所操作的流涉及一个终端时(例如标准输入和标准

输出),使用行缓冲方式。因为标准I/O库每行的缓冲区长度是固定的,所以只要填满了缓冲区,即使还没有遇到换行符,也会执行I/O系统调用操作,默认行缓冲区

的大小为1024。

  3、无缓冲区:

无缓冲区是指标准I/O库不对字符进行缓存,直接调用系统调用。标准出错流stderr通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。

注:

  1、标准输入和标准输出设备:当且仅当不涉及交互作用设备时,标准输入流和标准输出流才是全缓冲的。

  2、标准错误输出设备:标准出错绝不会是全缓冲方式的。

  3、对于任何一个给定的流,可以调用setbuf()和setvbuf()函数更改其缓冲区类型。

下面我们通过如下程序来进一步了解缓冲区:

当打印到屏幕(标准输出):

当写到文件中:

那么为什么输出到屏幕只有5条输出命令而输出到文件有7条输出命令呢?

  根据输出结果我们可以看出printf和fwrite重复写了两次,没有重复打印的是write.。

  printf和fwrite都是库函数:结合已有知识,我们了解到当使用库函数命令时,打印消息并没有直接写到输出位置上,而是 先把数据写到输出缓冲区,在刷新至输

出位置。

    1、当输出目标位置为输出到显示器时,则刷新方式是行刷新;

    2、当输出目标位置为输出到文件中时,刷新方式由行缓冲变为全缓冲,全缓冲是指当把缓冲区写满后才能刷新。(或者强制刷新)

  代码中printf和fwrite第一次打印,在fork操作之前,第二次在fork操作之后,原因是因为在fork操作前,printf和fwrite的输出命令将数据先写到缓冲区中,此时

只执行了这两条命令,由于是全缓冲的刷新方式,所以这两条命令并不足以将缓存写满,所以数据暂存在缓冲区中;然后进行fork创建子进程,由于fork创建出的父子

进程代码共享,而数据不共享,各自私有一份,缓冲区中的数据都属于数据,因为父进程的残留数据还在缓冲区中,所以fork完毕后,父子进程将缓存中的数据各自存

一份有父进程残留数据的数据,所以当父子进程各自刷新时,父子进程会各自执行一次printf和fwrite的输出命令,所以命令就从原来的两条变为四条。

struct
file 的其他重要成员有:.
  1.mode_t f_mode;
      文件模式确定文件是可读的或者是可写的(或者都是), 通过位 FMODE_READ 和FMODE_WRITE. 你可能想在你的 open 或者 ioctl 函数中检查这个成员的读写

许可, 但是不需要检查读写许可, 因为内核在调用你的方法之前检查. 当文件还没有为那种存取而打开时读或写的企图被拒绝, 驱动甚至不知道这个情况.

  2.loff_t f_pos;
      当前读写位置.
loff_t 在所有平台都是 64 位( 在 gcc 术语里是 long long ). 驱动可以读这个值,如果它需要知道文件中的当前位置, 但是正常地不应该改变它; 读

和写应当使用它们作为最后参数而收到的指针来更新一个位置, 代替直接作用于 filp->f_pos. 这个规则的一个例外是在 llseek 方法中, 它的目的就是改变文件位置.

  3.unsigned int f_flags;
      这些是文件标志, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驱动应当检查O_NONBLOCK 标志来看是否是请求非阻塞操作; 其他标志很少使用. 特别地,

应当检查读/写许可, 使用 f_mode 而不是f_flags. 所有的标志在头文件<linux/fcntl.h> 中定义.


  4.struct file_operations *f_op;
      和文件关联的操作. 内核安排指针作为它的open 实现的一部分, 接着读取它当它需要分派任何的操作时. filp->f_op 中的值从不由内核保存为后面的引用; 这意味

着你可改变你的文件关联的文件操作, 在你返回调用者之后新方法会起作用. 例如, 关联到主编号 1 (/dev/null,
/dev/zero, 等等)的 open 代码根据打开的次编号来替

代 filp->f_op 中的操作. 这个做法允许实现几种行为, 在同一个主编号下而不必在每个系统调用中引入开销. 替换文件操作的能力是面向对象编程的"方法重载"的内核对

等体.


  5.void *private_data;
      open 系统调用设置这个指针为 NULL, 在为驱动调用 open 方法之前. 你可自由使用这个成员或者忽略它; 你可以使用这个成员来指向分配的数据, 但是接着你必须

记住在内核销毁文件结构之前, 在 release 方法中释放那个内存. private_data 是一个有用的资源, 在系统调用间保留状态信息, 我们大部分例子模块都使用它.


  6.struct dentry *f_dentry;
关联到文件的目录入口( dentry )结构. 设备驱动编写者正常地不需要关心 dentry 结构, 除了作为 filp->f_dentry->d_inode 存取 inode 结构.

时间: 2024-10-10 23:52:01

Linux--struct file结构体的相关文章

Linux struct file 结构

struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.11内核)中,其原型是:struct file {        /*         * fu_list becomes invalid after file_free is called and queued via         * fu_rcuhead for RCU freeing         */        union {                struct l

Linux_Struct file()结构体

struct file结构体定义在/linux/include/linux/fs.h(Linux 2.6.11内核)中,其原型是:struct file {        /*         * fu_list becomes invalid after file_free is called and queued via         * fu_rcuhead for RCU freeing         */        union {                struct l

linux内核中的struct rlimit结构体详解

   在linux内核中,对一个进程获取系统资源的数量进行了限制.那么linux内核是如何实现这种对一个进程的各种资源的限制呢?    linux使用struct rlimit结构体来实现的,rlimit是 resource limit的缩写.    struct rlimit           {               unsigned int rlim_cur;  /* soft limit */               unsigned int rlim_max;  /* ha

file结构体中private_data指针的疑惑【转】

本文转载自:http://www.cnblogs.com/pengdonglin137/p/3328984.html hi all and barry, 最近在学习字符设备驱动,不太明白private_data在字符驱动中的作用,我们在 驱动中添加一个设备结构体,然后定义了这个结构体的全局指针变量,接着我们就能在 驱动程序中使用这个指针了.我看到很多驱动程序中都把结构体指针付给private_data, 然后对private_data操作. 为什么要使用private_data,难道仅仅是避免使

FILE 结构体的定义,inode ,软链接和硬链接的理解

一.FILE结构体: C将每个文件简单地作为顺序字节流.每个文件用文件结束符结束,或者在特定字节数的地方结束,这个特定的字节数可以存储在系统维护的管理数据结构中.当打开文件时,就建立了和文件的关系. 在开始执行程序的时候,将自动打开3个文件和相关的流:标准输入流.标准输出流和标准错误.流提供了文件和程序的通信通道.例如,标准输入流使得程序可以从键盘读取数据,而标准输出流使得程序可以在屏幕上输出数据.打开一个文件将返回指向FILE结构(在stdio.h中定义)的指针,它包含用于处理文件的信息,也就

struct socket结构体详解

在内核中为什么要有struct socket结构体呢?    struct socket结构体的作用是什么?    下面这个图,我觉得可以回答以上两个问题.      由这个图可知,内核中的进程可以通过使用struct socket结构体来访问linux内核中的网络系统中的传输层.网络层.数据链路层.也可以说struct socket是内核中的进程与内核中的网路系统的桥梁.   struct socket {      socket_state  state; // socket state  

struct list_head结构体及相关函数

struct list_head结构体是linux实现数据结构双向链表的基础.其定义: struct list_head { struct list_head *next, *prev; }; 可见链表里面的成员还是链表,每个链表都指向了前面和后面的链表. 一般将struct list_head作为一个成员,放到一个结构体中,其作用是可以从当前的结构体指针,获取到下一个链表元素的地址.一般用list_entry()来实现.具体按照下面的链接: http://www.cnblogs.com/bas

FILE结构体

FILE结构体用于文件操作,定义在C语言的stdio.h头文件中 我们通常所写的FILE *fp; 定义了一个指向该结构体的指针,通过fopen()返回一个指向要打开(或写入.创建)文件的指针 结构体中的成员_file实际上是一个描述符,用于进入打开文件表索引的指针 下图是我在VS2013中截的图 #ifndef _FILE_DEFINEDstruct _iobuf { char *_ptr;      //文件输入的下一个位置 int _cnt;        //当前缓冲区的相对位置 cha

struct sk_buff结构体详解

struct sk_buff是linux网络系统中的核心结构体,linux网络中的所有数据包的封装以及解封装都是在这个结构体的基础上进行. struct sk_buff_head  {     struct sk_buff *next;     struct sk_buff *prev;          __u32 qlen;     spinlock_t lock; } struct sk_buff {     struct sk_buff *next;     struct sk_buff