Fork me on GitHub

初级文件IO——利用dup、dup2实现文件重定位

API参考:初级文件IO——概述、API

dup复制文件描述符

使用dup、dup2复制方式实现文件共享时,不管复制出多少个文件描述符,它们永远只有一个文件表,所以使用所有描述符去操作文件时,最后使用的都是通过同一个文件位移量,不管谁操作后文件位移量都会被更新,因此不会出现覆盖。

什么是重定位

某文件描述符原来指向了A文件,输出数据是输出到A文件,但是重定位后,文件描述符指向了B文件,输出时数据输出到了B文件,这就是重定位。所谓重定位,说白了就是,文件描述符所指向的文件该变了,使得数据输出的目标文件也随之变。

回顾printf与write的关系

printf输出时,原本通过1,将数据输出到标准输出文件(显示器)的,但是现在,我想让printf输出到file.txt文件,而不是输出到屏幕,应该怎么办?

最简单的办法是就是,把printf函数调用的write函数里面的1,改成指向file.txt文件的新描述符即可,但是不幸的是write中的1写死了,1这个数字改不了,怎么办?

1这个数改不了,但是可以对1进行重定位,让1不再指向标准输出文件,而是指向file.txt,printf的数据,就输出到了file.txt文件中。

实现步骤

①open file.txt文件,返回一个文件描述符,比如3

3 ——> file.txt

②close(1),不要再让1指向标准输出文件(/dev/stdout)

③ 使用dup、dup2把3复制到1上,让1也指向file.txt文件

1这个文件描述符就被重定位了,凡是通过1输出的数据,都被写到了file.txt中,printf底层调用的是write(1, ...),用的也是1,printf的数据就被输出到了file.txt中。相当于printf函数的输出目的地,被重定位为了新的文件,这就是重定位。

代码演示

 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/stat.h>
 4 #include <fcntl.h>
 5 #include <stdlib.h>
 6 #include <unistd.h>
 7 
 8 #define FILE_NAME "./file.txt"
 9 
10 void print_error(char * str)
11 {
12     perror(str);
13     exit(-1);
14 }
15 
16 int main(void)
17 {
18     int fd1 = 0;
19     int fd2 = 0;
20     
21     fd1 = open(FILE_NAME, O_RDWR|O_TRUNC);
22     if(-1 == fd1) print_error("1 open fail");
23     //close(1);
24     //dup(fd1);
25     
26     dup2(fd1, 1);
27     
28     //printf("fd2 = %d\n", fd2);
29     printf("hello world\n");    
30 
31     return 0;
32 }

什么时候会使用dup、dup2,来实现从定位

函数中的文件描述符值写死了,无法修改为新的描述符,但是你又希望该函数,把数据输出到其它文件中,此时就可以使用dup、dup2对该函数中的文件描述符,进行重定位,指向新的文件,函数就会将数据输出到这个新文件。

Shell下面的重定位

Shell下面重定位 命令(>)是dup、dup2的典型应用,这个命令在重定位时,就是调用dup、dup2函数来实现的。

>使用的例子

ls > file.txt

ls的结果原本是输出到显示器的,但是>从定位后,就输出到了file.txt文件。

具体从定位的过程

①>命令(程序)会open打开file.txt文件,假设返回的文件描述符是3

3——>file.txt

②ls命令(程序)原本会调用write(1, ...),将结果输出到标准输出文件(显示器),但是 >会调用dup2,把3复制到1上,实现重定位,让1也指向file.txt文件,ls的结果自然就输出到file.txt文件了。

 

posted @ 2019-01-15 22:55  克拉默与矩阵  阅读(534)  评论(0)    收藏  举报