文件控制 fcntl函数详解

摘要:本文主要讨论文件控制fcntl函数的基本应用.dup函数可以复制文件描述符,而fcntl函数与dup函数有着异曲同工之妙.并且还有更加强大的功能,可以获取或设置已打开文件的性质,操作文件锁.

1.fcntl函数

《重定向编程 dup和dup2》一文中,介绍了dup和dup2两个函数,函数是提供了复制一个现存的文件描述符的功能,而本文介绍的fcntl函数提供了进一步管理文件描述符的各种手段,用它可以对以打开的描述符执行各种控制操作,比如,可以像dup和dup2一样复制一个文件描述符,还有获取或设置文件描述符标志(只读、只写等等),操纵文件锁.

头文件:

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

定义函数:

int fcntl(int filedes, int cmd);
int fcntl(int filedes, int cmd, longarg);
int fcntl(int filedes, int cmd,structflock *lock);

返回值:若成功返回值依赖与cmd,若出错则返回-1.如果设置属性,正确返回0,错误返回-1;如果是读取属性,正确返回该属性值,错误返回-1.如,下例三个命令有特定的返回值:F_DUPFD、F_GETFD、F_GETFL以及F_GETOWN.

F_DUPFD:返回新的文件描述符.

F_GETFD:返回相应的标志.

F_GETFL以及F_GETOWN:返回一个进程ID或负的进程组ID.

函数说明:

函数第一个参数为欲修改属性的文件描述符,第三个整数总是整数或记录锁(记录锁这里不讨论),如果是记录锁,第三个参数则是指向一个结构体指针.

fcntl()对打开的文件描述符filedes执行各种控制操作,具体是那一操作则由第二个参数cmd决定,表1列出了该参数的所有允许值.根据参数cmd的值,有一些参数还要提供第三个参数,就是文件锁.

表1 fcntl函数cmd值以及描述

fcntl函数有5种功能:

1)复制一个现有的文件描述符(cmd=F_DUPFD).

2)获取或设置文件描述符标志(cmd=F_GETFD或F_SETFD).

3)获取或设置文件状态标志(cmd=F_GETFL或F_SETFL).

4)获得或设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).

5)获取或设置记录锁(cmd=F_GETLK或F_SETLF).

2.F_DUPFD

复制文件描述符filefes.新文件描述符最为函数返回值.新文件描述符具有以下特性:

(1)新描述符是尚未打开的各文件描述符中大于或等于第三个参数值(取正整数)中各值的最小值.

(2)新描述符与filedes共享同一个文件表项(类似于dup函数);即,新描述符与filedes原始文件相同的文件指针,相同的打开文件(或管道),相同的文件状态标志,相同的文件模式.如图2所示,fd=3与fd=1两个文件描述符是指向同一个文件表的.但是,新文件描述符有它自己的一套文件描述符标志,其FD_CLOEXEC文件描述符标志被清除.

(3)将与新文件描述符关联的close-on-exe标志设置为在各exec(2)系统调用之间保持打开状态.

当进程打开一个文件时,内核中的数据结构如图1所示,也就是在程序复制文件描述符之前,内核状态是这样子的。每个进程默认只能打开1024个文件描述符,当一个进程打开一个文件时,默认会从0开始查找未被使用的描述符,由于0,1,2默认被占用,所有一般从3开始使用。

图1 进程打开一个文件时的内核数据结构状态

文件表项:每一个打开的文件对应着一张文件表,文件表可以共享,当多个文件描述符指向同一个文件表时,文件表中的refcnt字段会相应变化.文件表中包含着文件状态标识:文件的打开模式(R,W,RW,APPEND,NOBLOCK等)、当前文件偏移量、refcnt:被引用数量、v节点指针:指向一个v节点表。

v结点表:每个文件对应一个v结点表,无论被多少个进程打开都只有一个,它包括v节点信息(主要是stat结构体中的信息),i节点信息等。

简单地说,复制文件描述符仅仅在当前进程打开的文件表项新增一项(图2:新增了fd=3这一项),两者(fd=1或fd=3)同时指向内核中的文件表信息,操作文件描述符任意一个会影响到另外一个.

图2 进程复制文件描述符后的内核数据结构状态

例子1:复制文件描述符,并使用复制前后的文件描述符往打开的文件写入信息.

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

void main()
{
        int fd,newfd;
        char *bufFD="Advanced Programming! write by fd\n";
        char *bufNewFD="Advanced Programming! write by NewFD\n";
        fd = open("test.txt",O_RDWR|O_CREAT,0644);
        if(fd==-1)
        {
                printf("open file error%m\n");
                exit(-1);
        }

        //开始复制了
        newfd = fcntl(fd,F_DUPFD);
        //使用fd写
        write(fd,bufFD,strlen(bufFD));
        close(fd);

        //使用newfd写
        write(newfd,bufNewFD,strlen(bufNewFD));

        if(close(newfd)==-1)
        {
                printf("close error\n");
        }
        printf("now the content of file :\n");
        system("cat test.txt");
        exit(0);
}

输出:

:Advanced Programming! write by fd

:Advanced Programming! write by NewFD

可以看出,对fd或newfd进行读写操作时对同一个文件操作,而且还可以看到fd关闭后,对newfd没有影响,使用newfd还可以操作打开的文件.

对于复制一个文件描述符这个问题,fcntl和dup函数是有异曲同工之妙.

调用:

dup(filedes);

等价于:

fcntl(filedes, F_DUPFD, 0);

而调用:

dup2(filedes,filedes2);

等价于:

close(filedes2);
fcntl(filesdes,F_DUPFD,filedes);

注意:对于后一种情况,dup2并不完全等价于close加上fcntl.区别:

(1)dup2是原子操作,而close及fcntl则包括两个函数调用.有可能在close和fcntl之间插入执行信号捕获函数,中间这个过程修改了文件描述符.

(2)dup2和fcntl有某些不同的errno.

3.F_GETFL

F_GETFL用于获取文件状态标志和其访问模式,对应于filedes的文件状态标志作为返回值.F_GETFL支持的标志.如表2.

表2 文件状态标志说明

例子2:监测文件当前的读取权限.如果文件具有读取权限,则返回可读信息,如果具有写权限,则返回可写信息.否则返回出错信息.

#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        int accmode,val;
        if(argc!=2)
        {
                printf("error:\n");
        }
        if((val=fcntl(atoi(argv[1]),F_GETFL,0))<0)
        {
                printf("error:%m\n");
                exit(-1);
        }
        accmode = val & O_ACCMODE;
        switch(accmode)
        {
                case O_RDONLY:
                        printf("read only\n");
                        break;
                case O_WRONLY:
                        printf("write only\n");
                        break;
                case O_RDWR:
                        printf("read write\n");
                        break;
                default:
                        printf("unknow access mode\n");
        }
        exit(0);
}

输出:

:./a.out test.txt

:read write

4.综述

复制文件描述符的三种方法已学习的差不多,牢记dup、dup2和fcntl函数,因为,从此一生受用.关于fcntl的使用还有很多未挖掘,到这里先简单入门,日后再进一步加深学习.

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来,慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

时间: 2024-10-14 15:22:17

文件控制 fcntl函数详解的相关文章

(待续)文件IO详解(十六)---fcntl函数详解

fcntl函数是用来在进程中实现对文件的多种操作的函数,通过不同的命令可以实现不同的操作.常用的操作有复制文件描述符.为文件设置建议锁和获取设置文件控制标志等. ======================================================= 函数原型: ======================================================= 操作一:复制文件描述符实现文件共享 函数参数: fd:要操作的文件描述符 cmd:F_DUPFD ar

fcntl函数详解

功能描述:根据文件描述词来操作文件的特性. 文件控制函数          fcntl -- file control头文件: #include <unistd.h> #include <fcntl.h> 函数原型: int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock); 描述: fcntl()针对(文件)描述符

linux fcntl函数详解

转自:http://www.cnblogs.com/lonelycatcher/archive/2011/12/22/2297349.html 功能描述:根据文件描述词来操作文件的特性. #include <unistd.h>#include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock

php socket函数详解

转自:http://blog.163.com/[email protected]/blog/static/2889641420138213514298/ 最近在用socket实现服务端向客户端主动推送消息函数名 描述socket_accept() 接受一个Socket连接socket_bind() 把socket绑定在一个IP地址和端口上socket_clear_error() 清除socket的错误或最后的错误代码socket_close() 关闭一个socket资源socket_connec

delphi中的Format函数详解

首先看它的声明:[[email protected]][@21ki!] function Format(const Format: string; const Args: array of const): string; overload;[[email protected]][@21ki!] 事实上Format方法有两种形式,另外一种是三个参数的,主要区别在于它是线程安全的,[[email protected]][@21ki!]但并不多用,所以这里只对第一个介绍:[[email protect

c++ 虚函数详解

下面是对C++的虚函数的理解. 一,定义 简单地说,那些被virtual关键字修饰的成员函数,就是虚函数.虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离:用形象的语言来解释就是实现以共同的方法,但因个体差异而采用不同的策略.下面来看一段简单的代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 classA { publi

linux网络编程之shutdown() 与 close()函数详解

linux网络编程之shutdown() 与 close()函数详解 参考TCPIP网络编程和UNP: shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这个函数会关闭所有和A相关的套接字,包括复制的:而close能直接关闭套接字. 1.close()函数 [cpp] view plain copy print? <span style="font-size:13px;">#include<unistd.h> int 

linux中fork()函数详解[zz]

转载自:http://www.cnblogs.com/york-hust/archive/2012/11/23/2784534.html 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有

Python内置函数详解

置顶   内置函数详解 https://docs.python.org/3/library/functions.html?highlight=built#ascii 此文参考了别人整理好的东西(地址:http://www.cnblogs.com/sesshoumaru/p/6140987.html#p1),然后结合自己的理解,写下来,一方面方便自己,让自己好好学习,顺便回忆回忆:另一方面,让喜欢的盆友也参考一下. 经查询,3.6版本总共有68个内置函数,主要分类如下: 数学运算(7个) 类型转换