当前位置: 首页 > article >正文

IO重定向

文章目录

    • IO重定向
      • 概念
        • 3个标准文件描述符
        • “最低可用文件描述符”原则
      • 默认的连接:tty
      • 使用close then open将stdin定向到文件
      • 使用open..close..dup..close将stdin定向到文件
      • 使用open..dup2..close将stdin重定向到文件
      • 课上实验

IO重定向

  • 大多数的程序不接收输出文件名
    • 一般情况下将结果写到文件描述符1,并将错误消息写到文件描述符2
  • 如果希望将进程的输出写到文件或另一个进程的输入去,就必须重定向相应的文件描述符

概念

1.Unix进程使用文件描述符0,1,2作为标准输入、输入和错误的通道
2.当进程请求一个新的文件描述符时,系统内核将最低可用的文件描述符赋给它。

3个标准文件描述符

所有Unix都使用三种流的模型。
此模型通过一个简单的规则来实现。
三种流的每一种都是一个特别的文件描述符。
所有的Unix工具都使用文件描述符0,1,2

  • 标准文件描述符
    0: stdin
    1: stdout
    2: stderr
“最低可用文件描述符”原则
  • 文件描述符的概念:是一个数据的索引号。
  • 每个进程都有其打开的一组文件,这些打开的文件被保持在一个数组中。
  • 文件描述符即为某文件在些数组中的索引。

“最低可用文件描述符”原则:
当打开文件时,为此文件安排的描述符总是此数组中最低可用位置的索引。

默认的连接:tty

  • 通常通过shell命令运行Unix系统工具时,stdinstdoutstderr已连接在终端上。
    因此系统工具从键盘读取数据并把输出和错误消息写到屏幕。
    大部分的Unix工作处理从文件或标准输入读入的数据。
    如果在命令行上给出了文件名,工具将从文件读取数据。若无文件名,程序则从标准输入读取数据。

shell并不将重定向标记和文件名传递给程序,即重定向I/O的是shell而不是程序
重定向可以出现在命令行中的任何地方,并且在重定向标识符周围并不需要空格来区分
shell提供对重定向其他文件描述符的支持。
如: 2>file2,即重定向文件描述符2,将标准错误输出到给定的文件中

使用close then open将stdin定向到文件

  • 开始时,系统采用典型设置

    • 输入的数据流经过文件描述符0,输出流经过文件描述符1和2
    • 在这里插入图片描述
  • 第一步:close(0),将标准输入的连接挂断。
    文件描述符数组中的第一个元素处于空闲状态。

    • 在这里插入图片描述
  • 第二步,使用open(filename, O_RDONLY)打开一个想连接到stdin上的文件。

    • 当前最低可用文件描述符为0,因此打开的文件将被连接到标准输入上去
    • 在这里插入图片描述
  • 示例代码:

main()
{
    int fd ;
    char    line[100];
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );

    close(0);
    fd = open("/etc/passwd", O_RDONLY);
    if ( fd != 0 ){
        fprintf(stderr,"Could not open data as fd 0\n");
        exit(1);
    }

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
}

stdinredir1从标准输入读取并打印了三行字符串
接着重定向标准输入
之后从重定向的标准输入中读取并打印了三行字符串

使用open…close…dup…close将stdin定向到文件

在这里插入图片描述

  • 第一步:open(file)

    • 打开stdin将要重定向的文件。这个调用返回一个文件描述符,这个文件描述符不是0
    • 在这里插入图片描述
  • 第二步:close(0)

    • 将文件描述符0关闭
    • 在这里插入图片描述
  • 第三步:dup(fd)

    • 系统调用dup(fd)对文件描述符fd进行复制。此次复制使用最低可用文件描述符号。
    • 在这里插入图片描述
  • 第四步:close(fd)

    • 关闭文件的初始连接,只留下文件描述符0的连接。
    • 在这里插入图片描述
  • 示例代码

#include    <stdio.h>
#include    <fcntl.h>

main()
{
    int fd ;
    int newfd;
    char    line[100];

    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
    fd = open("/etc/passwd", O_RDONLY);   
    close(0);
    newfd = dup(fd); 
    if ( newfd != 0 ){
        fprintf(stderr,"Could not duplicate fd to 0\n");
        exit(1);
    }
    close(fd);      
    
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
}

使用open…dup2…close将stdin重定向到文件

在这里插入图片描述

  • 将 close(0)和dup(fd)结合在一起作为一个单独的系统调用dup2。
    dup2(old, new)将文件描述符old复制到文件描述符new。

    close(0); newfd = dup(fd);
    替换为
    newfd = dup2(fd,0); 即可。

课上实验

  • 使用dup或dup2,结合open/read/write/lseek实现标准输入或标准输出重定向

标准输入流重定向:我们将默认从终端的输入流改为从文件读取的输入流。
代码如下:

#include    <stdio.h>
#include    <fcntl.h>
#include 	<stdlib.h>
main()
{
    int fd ;
    int newfd;
    char    line[100];
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
 	fd = open("/etc/passwd", O_RDONLY);   
    close(0);
    newfd = dup(fd); 
    if ( newfd != 0 ){
        fprintf(stderr,"Could not duplicate fd to 0\n");
        exit(1);
    }
    close(fd);      
    fgets( line, 100, stdin ); printf("%s", line );
    fgets( line, 100, stdin ); printf("%s", line );
}

标准输出流重定向:将默认标准输出流改为某个文件
代码如下:

#include <stdio.h> 
#include <fcntl.h> 
#include <stdlib.h> 
#include <string.h>                                                                                                        
main()                                                                                                                      
{                                                                                                                           
    int fd ;                                                                                                                
    int newfd;                                                                                                              
        fd = open("abc.txt", O_WRONLY|O_CREAT|O_TRUNC,0644);                                                                
    close(1);                                                                                                               
    newfd = dup(fd);                                                                                                        
    if ( newfd != 1 ){                                                                                                      
        fprintf(stderr,"Could not duplicate fd to 1\n");                                                                    
        exit(1);                                                                                                            
    }                                                                                                                       
    close(fd);                                                                                                              
    char  line[]="我是标准输出,默认输出到终端,但我被重定向了,将被打印在重定向的位置";                                    
    write(1,line,strlen(line));                                                                                             
    close(newfd);                                                                                                           
}   
  • 分析:

    标准输出流卡了我很久,因为我每次重定向后abc.txt文件内容后面都会有一段乱码,像内存泄露一样乱码出现在abc.txt文件中,可当我将open的模式由O_WRONLY改为O_WRONLY | O_CREAT | O_TRUNC时,才能达到理想实验结果。总之使用 open(“abc.txt”, O_WRONLY | O_CREAT | O_TRUNC, 0644) 更为全面,既能确保文件不存在时创建它,又能确保在打开时清空文件内容,还可以设置新创建文件的权限。

结果如下:
在这里插入图片描述
在这里插入图片描述


http://www.kler.cn/news/336647.html

相关文章:

  • Java 中 MySQL 自增 ID 的与案例分析
  • 【unity进阶知识7】对象池的使用,如何封装一个对象池管理器
  • C#基础语法
  • 如何筛选网站有多少真实ip访问
  • Spring MVC的运行流程详解
  • Stable Diffusion的核心插件—ControlNet!万字长文解读!
  • AtCoder ABC374 A-D题解
  • 移动硬盘无法读取?原因、恢复方案与预防措施全解析
  • 【重学 MySQL】六十、空间类型
  • [C++题目]力扣155. 最小栈
  • SpringBootWeb快速入门!详解如何创建一个简单的SpringBoot项目?
  • 从被动防御到主动防护:等保测评的转型探索与实践
  • 图像转3D视差视频:DepthFlow、kling
  • webGL入门(六)图形旋转
  • 鸿蒙开发(NEXT/API 12)【申请使用受限权限】程序访问控制
  • Spring Boot医院管理系统:提升医疗服务效率
  • 解锁 Python 嵌套字典的奥秘:高效操作与实战应用指南
  • 【K8s】专题十四(1):Kubernetes 安全机制之 RBAC
  • android + tflite 分类APP开发-1
  • JDK1.2主要特性