文件描述符复制(dup,dup2)

目录

dup使用介绍

使用dup进行文件描述符复制

使用dup的缺陷分析

dup2使用介绍

dup2共享文件交叉写入测试

命令行重定位(使用重定位符号‘>’)


dup使用介绍

系统调用接口dup具体内容可以在终端使用指令man -2 dup

查看具体使用:

 int dup(int oldfd)用于对fd进行复制,指定新的fd,传入的参数oldfd为需要进行复制的初始fd

调用成功后返回值为复制得到的fd的数值。否则返回-1。

使用dup进行文件描述符复制

使用dup系统调用对fd进行复制时,会返回一个新的文件描述符( 如原来的fd是3,返回的fd值可能为4 )

示例代码如下:

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

int main(int argc,char *argv[])
{
	
	int fd1,fd2 = -1;
	fd1 = open("a.txt",O_RDWR | O_CREAT | O_TRUNC,0666) ;
	if (fd1==-1){
		perror("open failed");
	} 
	printf("fd1 = %d\n",fd1);
	fd2 = dup(fd1);
	printf("fd2 = %d\n",fd2);
	close(fd1);
}

 实际运行结果;


我们不能使用dup系统调用来指定复制后得到的fd为多少,复制后的fd是由操作系统内部自动分配的,分配的原则遵守fd分配的原则(即除去系统占用的fd0,1,2外,最小未被使用的fd。)
dup返回的fd和原来的oldfd都指向oldfd打开的那个动态文件,操作这两个fd实际操作的都是oldfd打开的文件。实际上构成了文件共享。
 

使用dup的缺陷分析

dup并不能指定分配的新的文件描述符的数字,dup2系统调用修复了这个缺陷,所以平时项目中实际使用时根据具体情况来决定用dup还是dup2.

系统文件提示符0、1、2这三个fd被标准输入、输出、错误通道占用。实际上我们可以关闭这三个fd。
我们可以close(1)关闭标准输出,关闭后,printf函数需要输出的内容就不再输出到标准输出中了。


我们可以使用系统调用接口dup重新分配得到1这个fd,这时候就把oldfd打开的这个文件和1这个标准输出通道相互绑定起来。这即为标准输出的重定位。

重定位如下:

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

int main(int argc,char *argv[])
{
	
	int fd1,fd2 = -1;
	//打开文件 
	fd1 = open("a.txt",O_RDWR | O_TRUNC);
	if (fd1==-1){
		perror("open failed");
	} 
	printf("fd1 = %d\n",fd1);
	close(1);//将系统fd标准输出关闭 
	fd2 = dup(fd1);
	printf("fd2 = %d\n",fd2);
	close(fd1); 
}

运行后结果为: 

 

因为进行了重定向,所以第二个printf的输出结果应该保存在了a.txt文档中,而不能标准输出在控制台。

我们查看a.txt的内容进行验证:


因此,我们可以使用close和dup接口配合使用。进行文件的重定位。

 dup2使用介绍

dup2和dup的作用一样,都是复制一个新的文件描述符。但是dup2允许用户
指定新的文件描述符的数字。
使用方法看man手册函数原型:

dup2共享文件交叉写入测试

dup2复制的文件描述符,和原来的文件描述符虽然数值不一样,但是指向同一个打开的文件

假设交叉写入时,使用dup2写文件的结果是接续写。

我们通过代码检验;

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

int main(int argc,char *argv[])
{
	
	int fd1,fd2 = -1;
	//打开文件 
	fd1 = open("a.txt",O_RDWR | O_TRUNC |O_CREAT,0644);
	if (fd1==-1){
		perror("open failed");
	} 
	printf("fd1 = %d\n",fd1); 
	fd2 = dup2(fd1,7);
	while (1){
		sleep(1);
		write(fd1,"aa",2);
		printf("[write in aa]\n");
		sleep(2);
		write(fd2,"bb",2);
		printf("[write in bb]\n");
	} 
	close(fd1); 
}

 编译运行该程序

 查看写入文件

至此可知,交叉写入文件时,文件的最终结果是接续写。

命令行重定位(使用重定位符号‘>’)

 linux中的shell命令执行后,打印结果都是默认进入stdout的(本质上是因为这些命令,例如ls、pwd等,都是调用printf进行打印),所以我们可以在linux的终端shell中直接看到命令执行的结果。
能否想办法把ls、pwd等命令的输出给重定位到一个文件中(譬如2.txt)去?

实际上linux终端支持一-个重定位的符号>很简单可以做到这点。

如下为示例,将系统调用dup手册内容重定位写入a.txt文件中:

 查看a.txt内容:

发现成功地用重定位'>'将shell命令行的结果写入指定文件中。 

这里提到重定位‘>’是因为其原理和本节内容相关,使用到系统调用接口dup。因为>的实现原理,就是利用open+close+dup, 先调用open接口打开一个需要将结果写入的文件,然后调用close关闭stdout(标准输出),最后调用dup接口将用于系统输出的文件标识符1和需要写入的文件关联起来(复制oldfd)即可。


 

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕逾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值