Unix编程实践教程笔记(四) IO重定向

IO重定向

//将stdin(标准输入)重定向到文件的第一个方法

// 策略解释:
// close then open
// 先使用close将标准输入的连接切断

// 使用open打开连接到stdin的文件
// 当前可用的文件描述符最低位0,因此所打开的文件将被连接到标准输入上去

// 如此:所有从标准输入读取数据的函数都将从此文件中读入

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>

int main()
{
    int fd;
    char line[100];
    fgets(line,100,stdin);printf("%s",line);
    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,"open fd 0 failed\n");
        exit(1);
    }
    fgets(line,100,stdin);printf("%s",line);
    fgets(line,100,stdin);printf("%s",line);
    fgets(line,100,stdin);printf("%s",line);
    return 0;
}
root@ziggy-virtual-machine:~/unix_linux/chapter10# ./stdinredir1 
line1
line1
line2
line2
line3
line3
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

方法2 open close dup open

系统调用dup建立指向已经存在的文件描述符的第二个连接

image

#include <unistd.h>

       int dup(int oldfd);
       int dup2(int oldfd, int newfd);
//将stdin(标准输入)重定向到文件的第一个方法

// 策略解释:
// close then open
// 先使用close将标准输入的连接切断

// 使用open打开连接到stdin的文件
// 当前可用的文件描述符最低位0,因此所打开的文件将被连接到标准输入上去

// 如此:所有从标准输入读取数据的函数都将从此文件中读入

#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
#include<stdlib.h>

int main()
{
    int fd;
    int newfd;
    char line[100];
    fgets(line,100,stdin);printf("%s",line);
    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);//对fd做一个复制,使用最低可用文件描述符,所以为0
    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);
    fgets(line,100,stdin);printf("%s",line);
    return 0;
}
root@ziggy-virtual-machine:~/unix_linux/chapter10# ./stdinredir2
now 
now
a
a
new input
new input
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin

方法3 open dup2 close

image

为程序重定向IO,例如:who>userlist

fork后,子进程继承了父进程指向打开文件的指针

(1)初始情况:开始时,进程运行在用户空间,文件描述符1连接打开的文件f上

(2)fork后,在新的进程中,包含与父进程相同的代码,数据,和打开文件的文件描述符,因此1仍然是指向f

子进程调用close(1),父进程中的1仍然指向f,子进程中文件描述符变为最低未用文件描述符

子进程调用create("g",m);

1连接到g,子进程的标准输出重定向到g

调用who后:

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/wait.h>
#include<sys/types.h>
int main()
{
    int pid;
    int fd;
    if((pid=fork())==-1)
    {
        perror("fork");
        exit(1);
    }
    if(pid==0)
    {
        close(1);
        fd =creat("userlist",0644);
        execlp("who","who",NULL);
        perror("execlp");
        exit(1);
    }
    if(pid!=0)
    {
        wait(NULL);
        printf("child run who done,results in userlist\n");
    }
    return 0;

}
/*

root@ziggy-virtual-machine:~/unix_linux/chapter10# ls
stdinredir1    stdinredir2    userlist   whotofile.c
stdinredir1.c  stdinredir2.c  whotofile
root@ziggy-virtual-machine:~/unix_linux/chapter10# cat userlist 
root     tty7         2021-10-28 08:24 (:0)

*/

管道编程

使用管道来连接一个进程的输出和另一个进程的输入

who|sort

/*
root@ziggy-virtual-machine:~/unix_linux/chapter10# who|sort
root     tty7         2021-10-28 08:24 (:0)
*/
       #include <unistd.h>

       int pipe(int pipefd[2]);
// 返回-1发生错误,0成功
//pipefd[0]为读取端 pipefd[1]为写入端(这是两个文件描述符)
//管道调用也使用最低有效文件描述符

image

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>

#define BUFSIZE 100
int main()
{
    
    int pipefd[2];
    int len;
    char buf[BUFSIZE];
    if(pipe(pipefd)==-1)
    {
        perror("could not make pipe");
        exit(1);
    }
    printf("got a pipe,the file edscriptors:{%d %d}\n",pipefd[0],pipefd[1]);
    //从标准输入读入数据,写入管道,从管道中读出,写出到标准输出
    while(fgets(buf,BUFSIZE,stdin))
    {
        len = strlen(buf);
        if(write(pipefd[1],buf,len)!=len)
        {
            perror("writing to pipe");
            break;
        }
        for(int i = 0;i<len;i++)
        {
            buf[i] = 'X';
        }
            len = read(pipefd[0],buf,BUFSIZE);
            if(len==-1)
            {
                perror("reading from pipe");
                break;
            }
            if(write(1,buf,len)!=len)
            {
                perror("writing to stdout");
                break;
            }

    }
    return 0;

    //由于所有的数据都以buf为缓冲,所以在管道读取端读取数据到buf
    // 时,最好先将其中的数据覆盖为其他数据(抹除)以体现管道写入读出的数据
}

image

使用fork来管理管道

一个进程创建了管道后,它拥有这个管道的两端的连接,这个进程fork创建子进程时,子进程也会得到这两个连接,所以父子进程都可以管道读写数据

最好是一个进读的时候,另一个进程写数据

image

#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<fcntl.h>
#include<pthread.h>

#define CHILD_MESSGE "I want a cookie\n"
#define PAR_MESSGE "testing\n"
#define oops(m,x) { perror(m);exit(x); }
int main()
{
    int pipefd[2],len,read_len;
    char buf[BUFSIZ];
    if(pipe(pipefd)==-1)
    {
        oops("can not get a pipe",1);
    }
    switch (fork())
    {
    case -1:
        oops("can not fork",2);
        break;
    case 0:
        len = strlen(CHILD_MESSGE);
        while(1)
        {
            if(write(pipefd[1],CHILD_MESSGE,len)!=len)
            {
                oops("write pipe",3);
            }
            sleep(5);
        }        
        break;
    default://父进程
        len = strlen(PAR_MESSGE);
        while(1)
        {
            if(write(pipefd[1],PAR_MESSGE,len)!=len)
            {
                oops("write",3);
            }
            sleep(1);
            read_len = read(pipefd[0],buf,BUFSIZ);
            if(read_len<=0)
            {
                break;
            }
            write(1,buf,read_len);
        }
    }
    return 0;
}

image

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值