linux-dup-dup2

dunp和dup2详解

转:https://www.cnblogs.com/linuxAndMcu/p/7668138.html

正常的文件描述符:

 

在linux下,通过open打开以文件后,会返回一个文件描述符,文件描述符会指向一个文件表,文件表中的节点指针会指向节点表。看下图:

打开文件的内核数据结构

打开文件的内核数据结构

dup和dup2两个函数都可以用来复制打开的文件描述符,复制成功后和复制源共享同一个文件表。看下图:

执行dup后的内核数据结构

执行dup后的内核数据结构

 

(1)dup函数

fd1=dup(fd);

fd1和fd共享一个文件表(对fd进行什么操作,fd1也会有相应的操作,fd和fd1是同步的)。

具体解释:

 

#inclue<stdio.h>

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

#include<stdlib.h>

int main()

{

char buf[6]={0};

char buf1[6]={0};

int fd = open("file",O_RDWR|O_CREAT,0644);

if(fd < 0)

printf("open error");

printf("fd:%d\n",fd);

//输出fd=3;

write(fd,"hello,world",12);

lseek(fd,0,SEEK_SET);  //将文件偏移量置为0,就是从第一个字符开始读(h开始)

read(fd,buf,5);

printf("fd:%s",buf);//输出hello

int fd1 = dup(fd);

read(fd1,buf1,5); //之前做的是对fd的读写操作,并没有对fd1做任何操作。但在这对fd1进行了读,如果输出数据。说明fd和fd1是同步的(fd做了什么相当于fd1也做了什么)

printf("fd1:%s\n",buf1); //输出,worl

//既然输出的是fd中的内容,说明fd和fd1共用一个文件表,读到的是,worl,而不是hello(我们在上面将偏移量从第一个字符开始,输出hello之后,fd的偏移量距离开始有5个字符当我们再次读fd的时候,它是从第6个字符开始读的,很明显,第6个是逗号,往后读5个,就是,worl),说明偏移量是一致的。(其实不用写偏移量,因为共用文件表就意味着文件偏移量也共用)

printf("fd1:%d\n",fd1);//输出fd1 = 4

//fd=3不等于fd1说明不共用同一个文件描述符。这也是dup和dup2的区别。

close(fd);

close(fd1);

return 0;

 

}

(2)dup2函数

 

fd2 = dup2(fd,fd1);

fd2用的fd1(第二个参数)的描述符,用的fd(第一个参数)的文件(和fd共享一个文件表,当然也共享文件偏移量)

强调第几个参数是因为如果你写成fd2=dup2(fd1,fd);那么fd2 =fd,和fd1共享同一个文件表。

 

#inclue<stdio.h>

#include<sys/types.h>

#include<unistd.h>

#include<fcntl.h>

#include<stdlib.h>

int main()

{

int fd = open("file",O_RDWR|O_CREAT,0644);

if(fd < 0)

printf("open error");

printf("fd:%d\n",fd);

//输出fd=3;

int fd1 =open("text",,O_RDWR|O_CREAT,0644);

if(fd1 < 0)

printf("open error");

printf("fd1:%d\n",fd1);

//输出fd1=4;

int fd2 = dup2(fd,fd1);

printf("fd2:%d\n",fd2);

//输出fd2=4;

//fd1 =fd2=4;说明fd2使用了fd1的文件描述符。

 

char buf[12]="hello,world";

write(fd,buf,12); //我们对fd进行了写,并没有对fd2进行写

read(fd2,buf,12);//但是我们对fd2读的时候,如果没有写,怎么可能读出来呢

printf("fd2:%s\n",buf);//事实是读出来了

//输出fd2:hello,world    //说明fd和fd2共用一个文件表。

 

lseek(fd,5,SEEK_SET);//距离开始偏移5位,说明下次读的时候是从第6个开始,注意我们是对fd进行偏移,没有对fd2偏移

read(fd2,buf,5);  //但是如果读fd2结果是从第6个字符开始的

buf[5]=0; //如果不写这句,输出的buf是按照12个字符输出的。因为定义buf的时候数组中可以放12个字符。

printf("fd2:%s\n",buf);//输出fd2:,worl  //说明fd2和fd共享文件偏移量。

close(fd);

close(fd2);

return 0;

}

dup和dup2的区别

dup:fd1= dup(fd);目标描述符使用了fd的文件表

dup2:fd2 = dup2(fd1,fd)目标描述符使用了fd1的描述符,使用了fd的文件表

函数调用

dup函数的作用:复制一个现有的句柄,产生一个与“源句柄特性”完全一样的新句柄(也即生成一个新的句柄号,并关联到同一个设备)

dup2函数的作用:复制一个现有的句柄到另一个句柄上,目标句柄的特性与“源句柄特性”完全一样(也即首先关闭目标句柄,与设备断连,接着从源句柄完全拷贝复制到目标句柄)


dup和dup2都是系统服务,window平台对应DuplicateHandle函数


这两个函数常用于输出的重定向,定义这两个函数的头文件是unistd.h。
     
要提的是这个头文件同时定义了下面三个常量:
STDERR_FILENO = 2 标准错误输出
STDIN_FILENO = 0 标准输入
STDOUT_FILENO = 1 标准输出

     

int fd, fd2;
mode_t fd_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;

void redir_stdout(const char *filename)
{
    fd2=dup(STDOUT_FILENO);
    fd = open(filename, O_WRONLY|O_CREAT, fd_mode); //打开文件操作
    dup2(fd, STDOUT_FILENO); //把输出重定向到fd标识的文件
    close(fd);
}

fd2=dup(STDOUT_FILENO);说明fd2表示了标准输出
如果我们想把刚刚定向到fd的输出,再定向回标准输出,我们可以用下面的代码实现:


void resume_stdout() //恢复输出,把标准输出定向到fd2,fd2代表的是标准输出
{
    dup2(fd2, STDOUT_FILENO);  
    close(fd2);
}


#i nclude <io.h>
#i nclude <stdlib.h>
#i nclude <stdio.h>

void main( void )
{
   int old;
   FILE *new;

   old = _dup( 1 );  
                     
   if( old == -1 )
   {
      perror( "_dup( 1 ) failure" );
      exit( 1 );
   }
   write( old, "This goes to stdout first\r\n", 27 );
   if( ( new = fopen( "data", "w" ) ) == NULL )
   {
      puts( "Can't open file 'data'\n" );
      exit( 1 );
   }

  
   if( -1 == _dup2( _fileno( new ), 1 ) )
   {
      perror( "Can't _dup2 stdout" );
      exit( 1 );
   }
   puts( "This goes to file 'data'\r\n" );

  
   fflush( stdout );
   fclose( new );

  
   _dup2( old, 1 );
   puts( "This goes to stdout\n" );
   puts( "The file 'data' contains:" );
   system( "type data" );
}


Output

This goes to stdout first
This goes to file 'data'

This goes to stdout

The file 'data' contains:

This goes to file 'data'

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值