【Linux修行路】基础I/O——重定向的实现原理

海哥  金牌会员 | 2024-8-21 00:39:18 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 535|帖子 535|积分 1605


目录
⛳️推荐
一、再来理解重定向
1.1 输出重定向效果演示
1.2 重定向的原理
1.3 dup2
1.4 输入重定向效果演示
1.5 输入重定向代码实现
二、再来理解标准输出和标准错误
2.1 同时对标准输出和标准错误举行重定向
2.2 将标准输出和标准错误重定向到同一个文件
三、再看一切皆文件


⛳️推荐

   前些天发现了一个巨牛的人工智能学习网站,平凡易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站
  一、再来理解重定向

1.1 输出重定向效果演示


分析:ls 指令是体现当前目录下的文件,本质就是将当前目录下所有的文件名以字符串的情势写入到体现器文件。采用输出重定向 >,将本来应该写入体现器文件的内容写入到了 log.txtx 文件中。
1.2 重定向的原理

在解说重定向原理前,我们需要明确文件描述符的分配规则,即从0下标开始,寻找最小的没有利用的数组位置,它的下标就是新打开文件的文件描述符。这里没有利用的意思是该下标里面存的是 NULL,即没有指向任何一个文件对象。下面通过一段代码来为大家展示重定向的原理。
  1. // mytest.c
  2. int main()
  3. {
  4.     close(1);
  5.     int fd = open(FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  6.     if(fd < 0)
  7.     {
  8.         perror("open");
  9.         return errno;
  10.     }
  11.     const char* str = "Hello Linux!\n";
  12.     int cnt = 5;
  13.     while(cnt--)
  14.     {
  15.         write(1, str, strlen(str));
  16.     }
  17.     return 0;
  18. }
复制代码
代码分析:上面这段代码就完善的展示了重定向的原理。首先调用 close 体系调用将 1 号下标对应的文件关闭,关闭的意思就是将 1 下标里的内容置为 NULL,本来 1 下标里面存储的内容是体现器文件对象的地址,也就是标准输出 stdout,紧接着调用 open 打开了一个文件,根据文件描述符的分配规则,新打开的这个文件的文件描述符就是 1,即文件描述符表(file*的数组)1 号下标里面存储的就是新打开的文件对象的地址。接下来调用 write 接口,向 1 号文件描述符中举行写入,本来 1 号文件描述符对应的是体现器文件,本来向体现器文件中写入的内容,此时就被写入到新打开的文件中,没有向体现器文件中写入,因此屏幕上就不会出现字符串,至此整个重定向的过程就竣事啦。

总结:重定向的本质是对数组下标里面的内容举行修改。

1.3 dup2

上面介绍了重定向的原理,下面介绍一下实现重定向的体系调用 dup2。
  1. #include <unistd.h>
  2. int dup2(int oldfd, int newfd);
复制代码
dup2 的具体实现并不是向上面代码中那样,先将一个文件描述符关闭,然后紧接着再打开一个文件。dup2 的利用方法是,用户在调用 dup2 接口前,正常打开一个文件,不用将体现器文件关闭,此时新打开文件的文件描述符就是 3。接下来调用 dup2 ,将新打开文件的文件描述符作为 oldfd,将体现器文件的文件描述符也就是 1,作为 newfd。我们知道,文件描述符本质上就是数组下标,dup2 函数中实验的工作就是将 oldfd 下标里存储的文件对象地址拷贝到 newfd 下标里面,至此重定向工作就完成了。

小Tips:dup2 的函数形参有一个误导,我们可能会觉得新打开文件的描述符是 newfd,其实否则,这里的 newfd 是将要被覆盖的文件描述符,oldfd 是新打开文件的描述符。

代码分析:上面就是输出重定向的实现原理,追加重定向只需要把 O_TRUNC 替换成 O_APPEND。
1.4 输入重定向效果演示


分析:cat 指令本来是从键盘文件中获取输入然后写入体现器文件中,采用输入重定向 < 后,是从 log.txt 文件中获取输入然后写入体现器文件中。
1.5 输入重定向代码实现

  1. // 输入重定向
  2. int main()
  3. {
  4.     int fd = open(FILE_PATH, O_RDONLY);
  5.     if(fd < 0)
  6.     {
  7.         perror("open");
  8.     }
  9.     dup2(fd, 0);
  10.     char str[1024];
  11.     ssize_t ret = read(fd, str, sizeof(str) - 1);
  12.     if(ret > 0)
  13.     {
  14.         str[ret] = '\0';
  15.         printf("echo: %s", str);
  16.     }
  17.     return 0;
  18. }
复制代码

小Tips:进程历史打开的文件与举行的各种重定向关系都和未来举行的程序替换无关,程序替换并不影响文件访问。进程打开文件和何种重定向工作,本质上都是进程管理的模块,而程序替换只会把用户空间的代码和数据完全被新程序替换,不会影响到进程管理。
二、再来理解标准输出和标准错误

  1. int main()
  2. {
  3.     fprintf(stdout, "Standard output messages\n");
  4.     fprintf(stdout, "Standard output messages\n");
  5.     fprintf(stdout, "Standard output messages\n");
  6.     fprintf(stderr, "Standard error messages\n");
  7.     fprintf(stderr, "Standard error messages\n");
  8.     fprintf(stderr, "Standard error messages\n");
  9.     return 0;
  10. }
复制代码

代码分析:> 是输出重定向,也就是对标准输出(1号文件描述符)举行重定向。标准错误对应的2号文件描述符并没有举行重定向,因此标准错误消息仍然打印在了屏幕上。
2.1 同时对标准输出和标准错误举行重定向

  1. ./mytest 1>output.txt 2>error.txt
复制代码
小Tips:这段代码就是将1号文件描述符对应的标准输出文件重定向到 output.txt 文件,将2号文件描述符对应的标准错误文件重定向到 error.txt 文件。这样以来屏幕上就不会有任何输出。

2.2 将标准输出和标准错误重定向到同一个文件

  1. ./mytest 1>all.txt 2>&1
复制代码

小Tips:将标准输出和标准错误都重定向到 all.txt 文件中。
三、再看一切皆文件

所有利用计算机的动作,都是通过进程去实验的,所有的访问文件利用,都是通过进程去实现的,目前所有对文件的利用都依赖于进程。

小Tips:所有的外设都被抽象成了文件,每个外设都有自己的读写方法,不同的外设读写方法一定是不同的。但是我们在对文件举行读写利用的时间,始终调用的都是 read 和 write 方法,这是因为利用体系为我们提供了一个方法集类型 file_operations,该结构体里面都是函数指针类型,指向外设的各种方法,这就是多态的雏形。所谓的一切皆文件,就是利用体系帮我们封装了一层文件对象,进程对各种外设的利用,全都酿成了对文件的利用。
  1. sszie_t read(int fd)
  2. {
  3.         task_struct->files->fd_array[fd]->f_op->read();
  4. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表