文章目录
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。它们之间的区别:
- dup2是一个原子操作,而close和fcntl包括两个函数调用。
- dup2和fcntl有一些不同的errno。