APUE读书笔记(三) 函数dup和函数fcntl

1 函数dup

函数dup和dup2都是用来复制一个现有的文件描述符,并和复制的对象共享已打开的文件。
在这里插入图片描述

1.1 dup函数原型

#include<unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);

1.2 参数说明

fd:文件描述符
fd2:指定新描述符的值

1.3 返回值

若成功,返回新的文件描述符;若出错,返回-1。
由dup返回的新文件描述符一定是当前可用文件描述符中的最小数值。如上图中,fd(1)指向一个文件,利用fd复制fd为1的文件描述符,此时返回当前可用文件描述符最小数值3,这两个fd共享同一个文件。
对于dup2,可以用fd2参数指定新描述符的值。如果fd2已经打开,则先将其关闭。如若fd等于fd2,则dup2返回fd2,而不关闭它。

1.4 示例

下面程序打开一个文件1.txt,其文件描述符为fd,利用dup函数复制fd至fd2,此时从标准输入读取数据并写入至fd2指向的文件,也即fd所指向的文件"1.txt"。

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

int main(int argc,char* argv[]){
        int fd;
        char buf[6];
        fd=open("../data/1.txt",O_RDWR|O_APPEND); //以追加方式打开
        if(fd<0)
                printf("open error!");
        int fd_dup=dup(fd);
        read(STDIN_FILENO,buf,5); //从标准输入写5个字节的数据到buf中
        write(fd_dup,buf,5); //将buf中的数据写入1.txt末尾

        close(fd);
        close(fd_dup);

        exit(0);
}

2 函数fcntl

2.1 fcntl函数原型

#include<fcntl.h>
int fcntl(int fd,int cmd,... /* int arg* /);

2.2 参数说明

fd:文件描述符
第3个参数:一般是一个整数,但是在说明记录锁时,第3个参数则是指向一个结构的指针
cmd:指定该函数的功能,facntl依赖cmd参数,有以下5种功能:

复制一个已有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)
获取/设置文件描述符标志(cmd=F_GETFD或F_SETFD)
获取/设置文件状态标志(cmd=F_GETFL或F_SETFL)
获取/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
获取/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)

我们在这儿说明这11中cmd的前8种,后3种与记录锁有关。

cmd功能
F_DUPFD复制文件描述符fd。新文件描述符作为函数值返回。它是尚未打开的各描述符中大于或等于第3个参数值(取为整型值)中各值的最小值。
F_DUPFD_CLOEXEC复制文件描述符,设置与新描述符关联的FD_CLOEXEC文件描述符标志的值,返回新文件描述符
F_GETFD对应于fd的文件描述符标志作为函数值返回。当前指定义了一个文件描述符标志FD_CLOEXEC
F_SETFD对应于fd设置文件描述符标志。新标志值按第3个参数设置(取为整型值)
F_GETFL对应于fd的文件状态标志作为函数返回,比如O_RDONLY、O_SYNC等。遗憾的是,5个访问方式标志(O_RDONLY、O_WRONLY、O_RDWR、O_EXEC、以及O_SEARCH)并不各占1位。因此首先必须用屏蔽字O_ACCMODE取得访问方式位,然后将结果与这5个值中的每一个相比较
F_SETFL将文件状态标志设置为第3个参数的值(取为整型值)。可以更改的几个标志是:O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC和O_ASYNC
F_GETOWN获取当前接收SIGIO和SIGURG信号的进程ID或进程组ID。
F_SETOWN设置接收SIGIO和SIGURG信号的进程ID或进程组ID。正的arg指定一个进程ID,负的arg表示等于绝对值的一个进程组ID。

2.3 返回值

若成功,则依赖于上述的cmd;若出错,返回-1。

2.4 示例

下面程序是将当前具有访问权限O_RDWR的文件修改成具有O_RDWR|O_NONBLOCK的权限,要记住,只有在当前进程中有效,如果进程退出,此文件的访问权限依旧是O_RDWR

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>
#include<sys/stat.h>

int main(int argc,char* argv[]){
        int fd,val;
        if(fd = open("../data/1.txt",O_RDONLY)<0) //以只读方式打开一个文件
               printf("open or create file error!");
        if((val=fcntl(fd,F_GETFL,0))<0)
                printf("fcntl error for fd %d",fd);
        switch (val & O_ACCMODE) //宏O_ACCMODE作为一个掩码与文件状态作AND位运算,产生一个表示文件访问模式的值
        {
                case O_RDONLY:
                        printf("read only");
                        break;
                case O_WRONLY:
                        printf("write only");
                        break;
                case O_RDWR:
                        printf("read write");
                        break;
                default:
                        printf("unknown access mode");
                        break;
        }
        if(val & O_APPEND)
                printf(",append");
        if(val & O_NONBLOCK)
                printf(",nonbloking");
        if(val & O_SYNC)
                printf(",synchronous writes");
#if !defined(_POSIX_C_SOURCE) && defined(O_FSYNC) && (O_FSYNC != O_SYNC)
        if(val & O_FSYNC)
                printf(",synchronous writes");
#endif
        putchar('\n');
        
//下面修改文件权限为O_RDWR|O_NONBLOCK
        int flags=O_NONBLOCK;
        val|=flags;
        if(fcntl(fd,F_SETFL,val)<0) //更改文件访问权限为O_RDONLY|O_NONBLOCK
                printf("fcntl error for fd %d",fd);
        if((val=fcntl(fd,F_GETFL,0))<0)
                printf("fcntl error for fd %d",fd);

        switch (val & O_ACCMODE) //宏O_ACCMODE作为一个掩码与文件状态作AND位运算,产生一个表示文件访问模式的值
        {
                case O_RDONLY:
                        printf("read only");
                        break;
                case O_WRONLY:
                        printf("write only");
                        break;
                case O_RDWR:
                        printf("read write");
                        break;
                default:
                        printf("unknown access mode");
                        break;
        }

        if(val & O_APPEND)
                printf(",append");
        if(val & O_SYNC)
                printf(",synchronous writes");
        if(val & O_NONBLOCK)
                printf(",nonblocking");
        putchar('\n');
        close(fd);
        exit(0);
}

在终端运行结果:
在这里插入图片描述

3 可以用fcntl函数实现dup函数

实际上,调用

	dup(fd);

等效于

	fcntl(fd,F_DUPFD,0);

而调用

	dup2(fd,fd2);

等效于

	close(fd2);
	fcntl(fd,F_DUPFD,fd2);

在后一种情况下,dup2并不完全等同于close加上fcntl。它们之间的区别:

  1. dup2是一个原子操作,而close和fcntl包括两个函数调用。
  2. dup2和fcntl有一些不同的errno。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值