xml地图|网站地图|网站标签 [设为首页] [加入收藏]

文件描述符FILE,互相转换实例解析

来源:http://www.ccidsi.com 作者:呼叫中心培训课程 人气:71 发布时间:2019-10-18
摘要:在求学Linux,在Linux下采纳c语言演习系统调用的时候,平常会际遇与公事有关的操作。平常来讲张开三个文件大家会获得这几个文件对于的文本叙述符fd“filedescriptor”;其他在另一些体

在求学Linux,在Linux下采纳c语言演习系统调用的时候,平常会际遇与公事有关的操作。平常来讲张开三个文件大家会获得这几个文件对于的文本叙述符fd“file descriptor”;其他在另一些体系调用里大家又一再遭逢FILE那一个结构。不知情最先是为啥,反正笔者一向感觉这两侧是全然同样的事物,FILE只但是是typedef后的int而已。直到有一天上机时碰着了竟然的题目,才被迫在man中详细读了file descriptor相关的东西,才发觉这两侧不是壹回事,并且双方混用的情况是不推荐的,很轻易带来意想不到的标题。

正文研讨的重假诺Linux普通话件陈述符fd与公事指针FILE*互动转换的相干内容,具体介绍如下。

文本陈述符与FILE,文件陈诉符FILE

其他通过查找,笔者找到了五个有关的函数:

1.文书陈述符fd的定义:文本呈报符在方式上是三个非负整数。实际上,它是二个索引值,指向内核为每一个进度所保证的该进程张开文件的记录表。当程序张开三个存世文件只怕创立叁个新文件时,内核向进程再次回到三个文件呈报符。在前后相继设计中,一些提到底层的程序编写制定往往会围绕着公文陈说符张开。不过文件汇报符这一概念往往只适用于UNIX、Linux那样的操作系统。

1. 文本汇报符(重点)

在Linux系统中全方位皆能够充当是文件,文件又可分为:普通文书、目录文件、链接文件和器械文件。文件陈说符(file descriptor)是水源为了神速管理已被张开的公文所开创的目录,其是一个非负整数(平日是小板寸),用于取代被展开的文书,全数实行I/O操作的系统调用都经过文件汇报符。程序刚刚启航的时候,0是正统输入,1是正统输出,2是标准错误。如若那时候去开荒一个新的文本,它的文本陈说符会是3。

fdopen():能够回到fd对应得(FILE *)结构而

2.文件指针FILE定义表明文件指针的貌似格局为:

1.1定义介绍

文本陈诉符的操作(如: open(),creat(),close(),read()))重临的是多少个文件描述符,它是int类型的大背头,即fd,其本质是文件汇报符表中的下标,它起到一个索引的功力,进度经过PCB中的文件叙述符表找到该fd所指向的文件指针filp。各类进程在PCB(Process Control Block)即经过调整块中都保留着一份文件描述符表,文件叙述符就是以此表的目录,文件陈说表中每一种表项都有叁个针对已开荒文件的指针; 已开采的文书在基础中用file结构体表示,文件陈诉符表中的指针指向file结构体。每张开多个文书,fd暗中认可从十分小的未被利用的下标初始分配。文件陈诉符的瑕疵:不可能移植到UNIX以外的类别上去,也不直观。

上面画张图来代表它们之间的涉嫌:图片 1

 而各种文件中又首要含有以下这个音讯:图片 2

fileno() 则恰恰相反,能够回来FILE*结构对应得 file descriptor。

FILE *指南针变量标记符;

1.2图片解释

file结构体中爱惜File Status Flag(file结构体的积极分子f_flags)和最近读写地方(file结构体的成员f_pos)。在上海教室中,进度1和进程2都开荒同一文件,不过对应分化的file结构体,由此得以有两样的File Status Flag和读写地方。file结构体中比较首要的分子还恐怕有f_count,表示援引计数(Reference Count),前面大家会讲到,dupfork等系统调用会促成多个文本叙述符指向同贰个file结构体,例如有fd1fd2都引用同二个file结构体,那么它的援用计数就是2,当close(fd1)时并不会放出file结构体,而只是把援用计数减到1,要是再close(fd2),援引计数就能够减到0同不常候释放file结构体,那才真正关闭了文件。

每个file布局体都指向三个file_operations结构体,那一个结构体的积极分子都以函数指针,指向完结种种文件操作的内核函数。譬喻在客户程序中read一个文件描述符,read通过系统调用步入基础,然后找到那些文件呈报符所指向的file结构体,找到file布局体所指向的file_operations结构体,调用它的read分子所指向的内核函数以完毕客户央浼。在客商程序中调用lseekreadwriteioctlopen等函数,最终都由基础调用file_operations的各成员所指向的内核函数完结客户央求。file_operations结构体中的release分子用于实现客户程序的close伸手,之所以叫release而不叫close是因为它不必然真正关闭文件,而是降低引用计数,只有援引计数减到0才关闭文件。对于同七个文件系统上打开的常规文件来讲,readwrite等文件操作的步调治将养办法应该是同样的,调用的函数应该是同一的,所以图中的八个张开文件的file结构体指向同一个file_operations结构体。倘诺张开一个字符设备文件,那么它的readwrite操作必然和正规文件不均等,不是读写磁盘的多少块而是读写硬件设施,所以file结构体应该本着不一样的file_operations结构体,个中的种种文件操作函数由该器械的驱动程序实现。

每个file结构体都有三个针对性dentry结构体的指针,“dentry”是directory entry(目录项)的缩写。我们传给openstat等函数的参数的是叁个门路,比方/home/akaedu/a,须要基于路线找到文件的inode。为了收缩读盘次数,内核缓存了目录的树状结构,称为dentry cache,当中各样节点是五个dentry结构体,只要本着路线各部分的dentry寻觅就能够,从根目录/找到home目录,然后找到akaedu目录,然后找到文件a。dentry cache只保留近年来探问过的目录项,若是要找的目录项在cache中从不,将要从磁盘读到内存中。

每个dentry结构体都有一个指南针指向inode结构体。inode结构体保存着从磁盘inode读上去的音讯。在上海教室的例证中,有三个dentry,分别代表/home/akaedu/a/home/akaedu/b,它们都针对同三个inode,表明那八个文本互为硬链接。inode结构体中保存着从磁盘分区的inode读上去消息,比如全部者、文件大小、文件类型和权杖位等。每一种inode结构体皆有叁个指向性inode_operations结构体的指针,后面一个也是一组函数指针指向一些完了文件目录操作的内核函数。和file_operations不同,inode_operations所指向的不是针对某三个文书举办操作的函数,而是影响文件和目录布局的函数,比方增多删减文件和目录、追踪符号链接等等,属于同一文件系统的各inode结构体能够本着同多个inode_operations结构体。

inode结构体有三个针对性super_block结构体的指针。super_block结构体保存着从磁盘分区的最棒块读上去的音信,比方文件系统类型、块大小等。super_block结构体的s_root成员是三个指向性dentry的指针,表示那个文件系统的根目录被mount到何地,在上图的例子中那一个分区被mount/home目录下。

filedentryinodesuper_block这么些结构体组成了VFS(设想文件系统VFS,Virtual Filesystem)的骨干概念。

但愿这么些新闻能对我们有用~

其间FILE应该为大写,它其实是由系统定义的一个布局,该协会中蕴藏文件名、文件状态和文件当前职分等消息。在编写源程序时不必关切FILE结构的内部原因。

1.3对文件陈诉符的操作

(1).查看Linux文件陈述符

 1 [[email protected] ~]# sysctl -a | grep -i file-max --color
 3 fs.file-max = 392036
 5 [[email protected] ~]# cat /proc/sys/fs/file-max
 7 392036
 9 [[email protected] ~]# ulimit -n
11 1024
13 [[email protected] ~]#

Linux下最大文件叙述符的限制有多少个方面,三个是顾客级的限量,另外二个则是系统级限制。

系统级限制:sysctl命令和proc文件系统中查看见的数值是同样的,那属于系统级限制,它是限制全部顾客展开文件汇报符的总额

顾客级限制:ulimit命令看见的是客户级的最大文件汇报符限制,也等于说每多个客商登陆后施行的次第占用文件陈说符的总额不可能超过那个界定

(2).修改文件陈述符的值

1 [[email protected] ~]# ulimit-SHn 10240
2 [[email protected] ~]# ulimit  -n
3 10240
4 [[email protected] ~]#

上述的修改只对当前会话起效果,是有时性的,假设急需永恒修改,则要修改如下:

1 [[email protected] ~]# grep -vE'^$|^#' /etc/security/limits.conf
2 *                hard nofile                  4096
3 [[email protected] ~]#

1 //默认配置文件中只有hard选项,soft 指的是当前系统生效的设置值,hard 表明系统中所能设定的最大值
2 [[email protected] ~]# grep -vE'^$|^#' /etc/security/limits.conf
3 *      hard         nofile       10240
4 *      soft         nofile      10240
5 [[email protected] ~]#
6 // soft<=hard soft的限制不能比hard限制高

(3).修改系统限制

1 [[email protected] ~]# sysctl -wfs.file-max=400000
2 fs.file-max = 400000
3 [[email protected] ~]# echo350000 > /proc/sys/fs/file-max  //重启后失效
4 [[email protected] ~]# cat /proc/sys/fs/file-max
5 350000
6 [[email protected] ~]#

//以上是权且更换文件陈说符
//恒久修改把fs.file-max=四千00增添到/etc/sysctl.conf中,使用sysctl -p就能够

图片 3

使用系统调用的时候用文件陈诉符的时候可比多,可是操作相比较原始。C库函数在I/O上提供了有个别有益于的包裹(举例格式化I/O、重定向),可是对细节的主宰远远不足。

1.4用程序查看文件陈说符

上面包车型大巴顺序,展开/home/shenlan/hello.c文件,假使此目录下未有hello.c文件,程序自动创建,程序中回到的文书陈诉符为3。因为经过运营时,展开了正规输入(0)、规范输出(1)和正式出错管理(2)多少个公文,fd默许从细微的未被采取的下标开始分配,因而回到的文书陈说符为3。

 1 #include<stdio.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 int main()
 7 {
 8        int fd;
 9        if((fd = open("/home/shenlan/fd.c",O_CREAT|O_WRONLY|O_TRUNC,0611))<0){
10               perror("openfile fd.c error!n");
11               exit(1);
12        }
13        else{
14               printf("openfile fd.c success:%dn",fd);
15        }
16        if(close(fd) < 0){
17               perror("closefile fd.c error!n");
18               exit(1);
19        }
20        else
21               printf("closefile fd.c success!n");
22        exit(0);
23 }

图片 4

进行结果:

图片 5

一经过于依赖此中的一种只会徒增麻烦,所以知道两岸的调换是很有必不可缺的。FILE*是对fd的封装

1.5进程打开三个文本的有血有肉流程    

经过经过系统调用open( )来展开一个文件,实质上是赢得多少个文书描述符,以便进度经过文件陈述符为连接对文本进行任何操作。进程张开文件时,会为该文件创立三个file对象,并把该file对象存入进度展开文件表中(文件陈说符数组),进而鲜明了所张开文件的文件陈诉符。        open( )操作在根本里经过sys_open( )实现的,sys_open( )将创设文件的dentry、inode和file对象,并在file_struct结构体的经过张开文件表fd_array[NR_OPEN_DEFAULT]中追寻三个空暇表项,然后回到那么些表项的下标(索引),即文件呈报符。成立文件的file对象时,将file对象的f_op指向了所属文件系统的操作函数集file_operations,而该函数集又来自现实文件的i节点,于是虚构文件系统就与事实上文件系统的操作衔接起来了。

本来,有人会说精晓文书路线的话再次展开正是了,但是那会发出竞争法规(Race Conditions),首先重新展开文件,相当于是2个fd指向同一文件,然后假若在展开的里边文件被删去了又被新建了叁个同名文件,2个fd指向的正是见仁见智的文件。

 2.C标准库中的FILE结商谈文件呈报符

C语言中利用的是文本指针实际不是文本陈说符做为I/O的句柄."文件指针(file pointer)"指向进度顾客区中的一个被喻为FILE结构的数据结构。FILE结构包涵二个缓冲区和三个文件陈述符值.而文件陈诉符值是文本陈说符表中的二个索引.从某种意义上说文件指针正是句柄的句柄。流(如: fopen)再次回到的是二个FILE结构指针, FILE结构是带有有文件叙述符的,FILE结构函数可以作为是对fd直接操作的种类调用的卷入, 它的长处是包含I/O缓存。

从文件描述符fd 到文件流 FILE* 的函数是
FILE* fdopen(int filedes,const char* mode);

图片 6

前期的C规范库中,FILE在stdio.h中定义;Turbo C中,参见谭浩强的《C程序设计》,FILE结构体中蕴涵成员fd,即文件叙述符。亦能够在安装的Ubuntu系统的/usr/include/stdio.h中找到struct _IO_FILE结构体,这一个结构体相比复杂,大家只关怀要求的一对-文件描述符,不过在这里个的结构体中,我们并不曾意识与公事陈述符相关的比方说fd成员变量。此时,类型为int的_fileno结构体成员引起了咱们的小心,不过不可能鲜明其为文件陈诉符。因而写个程序测量试验是最佳的艺术,能够用以下的代码测量试验:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<sys/types.h>
 4 #include<sys/stat.h>
 5 #include<fcntl.h>
 6 int main( )
 7 {
 8        char buf[50] = {"ILOVE this game!"};
 9        FILE *myfile;
10 
11        myfile = fopen("2.txt","w ");
12        if(!myfile){
13               printf("error:openfile failed!n");
14        }
15        printf("The openedfile's descriptor is %dn",myfile->_fileno);
16        if(write(myfile->_fileno,buf,50)< 0){
17               perror("error:writefile failed!n");
18               exit(1);
19        }else{
20               printf("writefile successed!n");
21        }
22        exit(0);
23 }

程序中,使用fopen函数以读写张开2.txt文本,即使海市蜃楼2.txt文件,则创设此文件。并将其归来的FILE指针myfile。使用printf向专门的学问终端打印出myfile->_fileno的值,并将myfile->_fileno作为文件叙述符传递给write系统调用,向展开的公文写入缓冲区数据。然后利用cat命令查看2.txt的剧情。实施的结果如图所示。_fileno的值为3,因为专门的学业输入、输出、出错为0、1、2。输出结果如下:图片 7
    因此,_fileno成员即为操作系统展开文件再次回到的句柄(windows系统)或文件汇报符。深远学习能够翻阅人民邮政和邮电通讯出版社《C规范库》。当然还可以阅读/glibc-2.9/manual/io.txti文件。Linux中,文件的叙说符分配是从小到大每一个查询文件呈报符是还是不是业已应用,然后再分配,也得以写程序测量检验。

 文件陈述符表也称文件陈述符数组,当中寄放了贰个经过所展开的全体文件。文件呈报符数组包蕴在经过张开的公文表files_struct结构中。在/include/linux/fdtable.h中定义,为三个指向file类型的指针数组---fd_array[NR_OPEN_DEFAULT],其中NR_OPEN_DEFAULT也在fdtable.h中定义,那是三个和具体的CPU连串布局有关的变量,#define NR_OPEN_DEFAULTBITS_PER_LONG。

FILE结议和文件描述符、file结构之间的涉嫌能够用下图来代表:

图片 8

 

1. 文件汇报符(重视) 在Linux系统中整整皆可以看作是文件,文件又可分为:普通文书、目录文件、链接...

glibc库提供了五个转移函数fdopen(3)和fileno(3),都以<stdio.h>中的

FILE *fdopen(int fd, const char *mode); int fileno(FILE *stream);

PS:为了节约篇幅,照旧继续忽视重临值的检查。

来看看测验呢,是还是不是大家想的那样。

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
  const char* filename = "new.txt";
  int fd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

  FILE* fp = fdopen(fd, "w ");
  int fd2 = fileno(fp);

  printf("fd=%d | fd2=%dn", fd, fd2);

  fclose(fp);
  close(fd);
  return 0;
}


$ gcc test.c 
$ ./a.out 
fd=3 | fd2=3

本文由68399皇家赌场发布于呼叫中心培训课程,转载请注明出处:文件描述符FILE,互相转换实例解析

关键词: 68399皇家赌场

最火资讯