五、文件IO——dup 函数

5.1 dup 函数---复制文件描述符

5.1.1 简单cat实现及输入输出重定向

  io.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 
13 #define BUFFER_LEN 1024
14 
15 /* 文件的读写拷贝 */
16 void copy(int fdin, int fdout)
17 {
18     char buff[BUFFER_LEN];
19     ssize_t size;
20 
21 //    printf("file length: %ld\n", lseek(fdin, 0L, SEEK_END));//将文件定位到文件尾部,偏移量为0L
22 //    lseek(fdin, 0L, SEEK_SET);// 定位到文件开头
23 
24     while((size = read(fdin, buff, BUFFER_LEN)) > 0) { //从 fdin 中读取 BUFFER_LEN 个字节存放入  buff 中
25 //        printf("current: %ld\n", lseek(fdin, 0L, SEEK_CUR));
26 
27         if(write(fdout, buff, size) != size) {
28             fprintf(stderr, "write error: %s\n", strerror(errno));
29             exit(1);
30         }
31     }
32     if(size < 0) {
33         fprintf(stderr, "read error:%s\n", strerror(errno));
34         exit(1); // 相当于 return 1;
35     }
36 }

  cat.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 int main(int argc, const char *argv[])
13 {
14     int fd_in = STDIN_FILENO;
15     int fd_out = STDOUT_FILENO;
16     int i;
17 
18     for(i = 1; i < argc; i++) {
19         fd_in = open(argv[i], O_RDONLY);
20         if(fd_in < 0) {
21             perror("open error");
22             continue;
23         }
24 
25         copy(fd_in, fd_out);
26         close(fd_in);
27     }
28 
29     if(argc == 1)
30         copy(fd_in, fd_out);
31 
32     return 0;
33 }

  编译:gcc -o bin/cat -Iinclude src/io.c src/cat.c

  调试:

  

  

  

  cat 的作用就输入和输出的重定向功能,而 dup 和 dup2 就是用来完成此功能的。

5.1.2 dup 和 dup2 函数说明

1 #include<unistd.h>
2 int dup (int oldfd);
3 int dup2(int odlfd,int newfd);
  • 函数说明:
    • dup() 用来复制参数 oldfd 所指的文件描述符,并将它返回。此新的文件描述符和参数oldfd指的是同一个文件,共享所有的锁定、读写位置和各项权限或旗标。例如,当利用 lseek() 对某个文件描述符作用时,另一个文件描述词的读写位置也会随着改变。不过,文件描述符之间并不共享 close-on-exec 旗标。  
    • dup2() 用来复制参数 oldfd 所指的文件描述符,并将它拷贝至参数 newfd 后一块返回。若参数 newfd 为一已打开的文件描述词,则 newfd 所指的文件会先被关闭。如若 oldfd 等于 newfd,则dup2 返回 newfd,而不关闭它。dup2() 所复制的文件描述符,与原来的文件描述符共享各种文件状态,详情可参考 dup() 。
  • 参数:
    • oldfd:原先的文件描述符
    • newfd:新的文件描述符  
  • 返回值:当复制成功时,则返回最小及尚未使用的文件描述符。若有错误则返回-1,errno会存放错误代码。
  • 附加说明:
    • dup2() 相当于调用 fcntl(oldfd,F_DUPFD,newfd);请参考 fcntl()  
    • 在进程间通信时可用来改变进程的标准输入和标准输出。

  文件描述符的赋值是文件描述符表结构体成员中指针的复制。

  

  dup2(fd_in, STDIN_FILENO),相当于就是将 fd_in 文件描述符中的指向文件表项的指针赋值给 STDIN_FILENO 中的指向标准输入的指针,此时,STDIN_FILENO 中的指针指向了fd_in 中的指针指向的文件表项(地址一样了),最终指向了读取的文件。

  则此时 dup1 中 STDIN_FILENO 不再是从标准输入读取,而是从 fd_in 中去读取。这种就是重定向

 5.1.3 实例

  将+ 和 - 改为输入输出重定向

   mcat.c

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <unistd.h>
 5 #include "io.h"
 6 #include <string.h>
 7 #include <errno.h>
 8 #include <stdlib.h>
 9 #include <stdio.h>
10 #include <fcntl.h>
11 
12 /*
13  * bin/mcat + append.txt(+ 为输入重定向)
14  * bin/mcat - append.txt(- 为输出重定向)
15  */
16 int main(int argc, const char *argv[])
17 {
18     int fd_in;
19     int fd_out;
20     int i;
21     int flag = 0;
22 
23     for(i = 1; i < argc; i++) {
24         if(!strcmp("+", argv[i])) {
25             fd_in = open(argv[++i], O_RDONLY);
26             if(fd_in < 0) {
27                 perror("open error");
28                 exit(1);
29             }
30 
31             //将标准输入重定向到文件
32             if(dup2(fd_in, STDIN_FILENO) != STDIN_FILENO) {
33                 perror("dup2 error");
34                 exit(1);
35             }
36 
37             close(fd_in);
38         } else if(!strcmp("-", argv[i])) {
39             fd_out = open(argv[++i], O_WRONLY | O_CREAT | O_TRUNC, 0777);
40             if(fd_out < 0) {
41                 perror("open error");
42                 exit(1);
43             }
44             
45             //将标准输出重定向到文件
46             if(dup2(fd_out, STDOUT_FILENO) != STDOUT_FILENO) {
47                 perror("dup2 error");
48                 exit(1);
49             }
50 
51             close(fd_out);
52 
53         } else {
54             flag = 1;
55             fd_in = open(argv[i], O_RDONLY);
56             if(fd_in < 0) {
57                 perror("open error");
58                 exit(1);
59             }
60 
61             if(dup2(fd_in, STDIN_FILENO) != STDIN_FILENO) {
62                 perror("dup2 error");
63                 exit(1);
64             }
65 
66             copy(STDIN_FILENO, STDOUT_FILENO);
67             close(fd_in);
68         }
69     }
70 
71     if(!flag) {
72         copy(STDIN_FILENO, STDOUT_FILENO);
73     }
74 
75     return 0;
76 }

  编译调试如下:

  

posted @ 2018-05-13 22:20  游戏进行中  阅读(462)  评论(0编辑  收藏  举报